@yielded/agent-storage-memory 0.1.0-beta.169 → 0.1.0-beta.171
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/MemoryMessageDeliveryStore.d.mts +1 -1
- package/dist/MemoryMessageDeliveryStore.mjs +28 -2
- package/dist/MemoryMessageDeliveryStore.mjs.map +1 -1
- package/dist/MemorySubmissionLedger.d.mts +1 -1
- package/dist/MemorySubscriptionStore.mjs +94 -18
- package/dist/MemorySubscriptionStore.mjs.map +1 -1
- package/dist/MemoryThreadStore.d.mts +1 -1
- package/dist/MemoryThreadStore.mjs +2 -9
- package/dist/MemoryThreadStore.mjs.map +1 -1
- package/dist/{MemoryThreadStoreKernel-DYNDjlhO.d.mts → MemoryThreadStoreKernel-h_k2t46J.d.mts} +2 -2
- package/dist/WorkSelection-CmqTuws3.mjs.map +1 -1
- package/package.json +1 -1
- package/src/MemoryMessageDeliveryStore.ts +43 -2
- package/src/MemorySubscriptionStore.ts +252 -99
- package/src/MemoryThreadStore.ts +2 -8
- package/src/internal/MemoryThreadStoreKernel.ts +1 -1
package/dist/{MemoryThreadStoreKernel-DYNDjlhO.d.mts → MemoryThreadStoreKernel-h_k2t46J.d.mts}
RENAMED
|
@@ -50,7 +50,7 @@ interface MemoryDeliveryTransfer {
|
|
|
50
50
|
readonly after: string;
|
|
51
51
|
}, ThreadStoreError>;
|
|
52
52
|
readonly startImport: (threadId: ThreadId) => Effect.Effect<MemoryDeliveryImport, ThreadImportRejected | ThreadStoreError>;
|
|
53
|
-
readonly
|
|
53
|
+
readonly peerCount: (threadId: ThreadId, nowMillis: number, limit: number) => number;
|
|
54
54
|
}
|
|
55
55
|
/** Native control metadata only; callers already hold the journal's shared gate. */
|
|
56
56
|
interface MemoryWorkOwner {
|
|
@@ -82,4 +82,4 @@ declare const MemoryThreadStoreKernel_base: Context.ServiceClass<MemoryThreadSto
|
|
|
82
82
|
declare class MemoryThreadStoreKernel extends MemoryThreadStoreKernel_base {}
|
|
83
83
|
//#endregion
|
|
84
84
|
export { MemoryThreadStoreKernel as t };
|
|
85
|
-
//# sourceMappingURL=MemoryThreadStoreKernel-
|
|
85
|
+
//# sourceMappingURL=MemoryThreadStoreKernel-h_k2t46J.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WorkSelection-CmqTuws3.mjs","names":[],"sources":["../src/internal/MemoryThreadStoreKernel.ts","../src/internal/WorkSelection.ts"],"sourcesContent":["import type { RunId, SubmissionId, ThreadId, ToolCallId } from \"@yielded/agent/identifiers\";\nimport type { IdempotencyKey } from \"@yielded/agent/receipt\";\nimport type { RecordEnvelope, RecordId } from \"@yielded/agent/records\";\nimport type { StorageOwner } from \"@yielded/agent/run-storage\";\nimport type { SubmissionSnapshot, WorkerLedgerState } from \"@yielded/agent/submission-ledger\";\nimport type {\n PreparedImportPage,\n ThreadImportReader,\n ThreadDeliveryImportReader,\n ThreadImportRejected,\n} from \"@yielded/agent/thread-import\";\nimport type {\n AppendResult,\n AppendRequest,\n ThreadStoreFailure,\n ThreadTail,\n ThreadAdmission,\n ThreadStoreError,\n ThreadExportSnapshot,\n} from \"@yielded/agent/thread-store\";\nimport type { TransferFacts, TransferSection } from \"@yielded/agent/thread-transfer\";\nimport type {\n ThreadWorkEntry,\n WorkThreadsRequest,\n WorkThreadsPage,\n} from \"@yielded/agent/thread-work\";\nimport { Context, type Effect, type Stream } from \"effect\";\n\nexport interface PreparedMemoryAppend {\n readonly request: AppendRequest;\n readonly batchJson: string;\n}\n\n/** Private storage, not a whole-Thread preparation value. Publication callbacks never yield. */\nexport interface MemoryLedgerImport {\n readonly reader: Pick<ThreadImportReader[\"Service\"], \"admission\" | \"runOwner\" | \"commands\">;\n readonly stage: (\n page: PreparedImportPage,\n ) => Effect.Effect<void, ThreadImportRejected | ThreadStoreError>;\n readonly prepareCommit: (\n workerSeal?: Pick<WorkerLedgerState, \"terminal\">,\n ) => Effect.Effect<() => void, ThreadImportRejected | ThreadStoreError, ThreadImportReader>;\n}\n\nexport interface MemoryLedgerTransfer {\n readonly snapshot: (threadId: ThreadId) => Effect.Effect<\n Omit<typeof ThreadExportSnapshot.Type, \"deliveries\"> & {\n readonly idle: boolean;\n readonly workerSeal?: Pick<WorkerLedgerState, \"terminal\">;\n },\n ThreadStoreError\n >;\n readonly facts: (\n threadId: ThreadId,\n section: Exclude<TransferSection, \"deliveries\">,\n after: string | undefined,\n ) => Effect.Effect<{ readonly facts: TransferFacts; readonly after: string }, ThreadStoreError>;\n readonly startImport: (\n threadId: ThreadId,\n ) => Effect.Effect<MemoryLedgerImport, ThreadImportRejected | ThreadStoreError>;\n readonly submissions: (threadId: ThreadId) => Stream.Stream<SubmissionSnapshot, ThreadStoreError>;\n readonly admission: (\n threadId: ThreadId,\n submissionId: SubmissionId,\n ) => Effect.Effect<ThreadAdmission | undefined, ThreadStoreError>;\n readonly commands: ThreadImportReader[\"Service\"][\"commands\"];\n}\n\nexport interface MemoryDeliveryImport {\n readonly record: ThreadImportReader[\"Service\"][\"delivery\"];\n readonly stage: (\n page: PreparedImportPage,\n ) => Effect.Effect<void, ThreadImportRejected | ThreadStoreError>;\n readonly has: (messageId: IdempotencyKey) => boolean;\n readonly prepareCommit: () => Effect.Effect<\n () => void,\n ThreadImportRejected | ThreadStoreError,\n ThreadDeliveryImportReader\n >;\n}\n\nexport interface MemoryDeliveryTransfer {\n readonly record: (\n threadId: ThreadId,\n messageId: IdempotencyKey,\n ) => ReturnType<ThreadImportReader[\"Service\"][\"delivery\"]>;\n readonly snapshot: (threadId: ThreadId) => {\n readonly idle: boolean;\n readonly deliveries: number;\n };\n readonly facts: (\n threadId: ThreadId,\n after: string | undefined,\n ) => Effect.Effect<{ readonly facts: TransferFacts; readonly after: string }, ThreadStoreError>;\n readonly startImport: (\n threadId: ThreadId,\n ) => Effect.Effect<MemoryDeliveryImport, ThreadImportRejected | ThreadStoreError>;\n readonly
|
|
1
|
+
{"version":3,"file":"WorkSelection-CmqTuws3.mjs","names":[],"sources":["../src/internal/MemoryThreadStoreKernel.ts","../src/internal/WorkSelection.ts"],"sourcesContent":["import type { RunId, SubmissionId, ThreadId, ToolCallId } from \"@yielded/agent/identifiers\";\nimport type { IdempotencyKey } from \"@yielded/agent/receipt\";\nimport type { RecordEnvelope, RecordId } from \"@yielded/agent/records\";\nimport type { StorageOwner } from \"@yielded/agent/run-storage\";\nimport type { SubmissionSnapshot, WorkerLedgerState } from \"@yielded/agent/submission-ledger\";\nimport type {\n PreparedImportPage,\n ThreadImportReader,\n ThreadDeliveryImportReader,\n ThreadImportRejected,\n} from \"@yielded/agent/thread-import\";\nimport type {\n AppendResult,\n AppendRequest,\n ThreadStoreFailure,\n ThreadTail,\n ThreadAdmission,\n ThreadStoreError,\n ThreadExportSnapshot,\n} from \"@yielded/agent/thread-store\";\nimport type { TransferFacts, TransferSection } from \"@yielded/agent/thread-transfer\";\nimport type {\n ThreadWorkEntry,\n WorkThreadsRequest,\n WorkThreadsPage,\n} from \"@yielded/agent/thread-work\";\nimport { Context, type Effect, type Stream } from \"effect\";\n\nexport interface PreparedMemoryAppend {\n readonly request: AppendRequest;\n readonly batchJson: string;\n}\n\n/** Private storage, not a whole-Thread preparation value. Publication callbacks never yield. */\nexport interface MemoryLedgerImport {\n readonly reader: Pick<ThreadImportReader[\"Service\"], \"admission\" | \"runOwner\" | \"commands\">;\n readonly stage: (\n page: PreparedImportPage,\n ) => Effect.Effect<void, ThreadImportRejected | ThreadStoreError>;\n readonly prepareCommit: (\n workerSeal?: Pick<WorkerLedgerState, \"terminal\">,\n ) => Effect.Effect<() => void, ThreadImportRejected | ThreadStoreError, ThreadImportReader>;\n}\n\nexport interface MemoryLedgerTransfer {\n readonly snapshot: (threadId: ThreadId) => Effect.Effect<\n Omit<typeof ThreadExportSnapshot.Type, \"deliveries\"> & {\n readonly idle: boolean;\n readonly workerSeal?: Pick<WorkerLedgerState, \"terminal\">;\n },\n ThreadStoreError\n >;\n readonly facts: (\n threadId: ThreadId,\n section: Exclude<TransferSection, \"deliveries\">,\n after: string | undefined,\n ) => Effect.Effect<{ readonly facts: TransferFacts; readonly after: string }, ThreadStoreError>;\n readonly startImport: (\n threadId: ThreadId,\n ) => Effect.Effect<MemoryLedgerImport, ThreadImportRejected | ThreadStoreError>;\n readonly submissions: (threadId: ThreadId) => Stream.Stream<SubmissionSnapshot, ThreadStoreError>;\n readonly admission: (\n threadId: ThreadId,\n submissionId: SubmissionId,\n ) => Effect.Effect<ThreadAdmission | undefined, ThreadStoreError>;\n readonly commands: ThreadImportReader[\"Service\"][\"commands\"];\n}\n\nexport interface MemoryDeliveryImport {\n readonly record: ThreadImportReader[\"Service\"][\"delivery\"];\n readonly stage: (\n page: PreparedImportPage,\n ) => Effect.Effect<void, ThreadImportRejected | ThreadStoreError>;\n readonly has: (messageId: IdempotencyKey) => boolean;\n readonly prepareCommit: () => Effect.Effect<\n () => void,\n ThreadImportRejected | ThreadStoreError,\n ThreadDeliveryImportReader\n >;\n}\n\nexport interface MemoryDeliveryTransfer {\n readonly record: (\n threadId: ThreadId,\n messageId: IdempotencyKey,\n ) => ReturnType<ThreadImportReader[\"Service\"][\"delivery\"]>;\n readonly snapshot: (threadId: ThreadId) => {\n readonly idle: boolean;\n readonly deliveries: number;\n };\n readonly facts: (\n threadId: ThreadId,\n after: string | undefined,\n ) => Effect.Effect<{ readonly facts: TransferFacts; readonly after: string }, ThreadStoreError>;\n readonly startImport: (\n threadId: ThreadId,\n ) => Effect.Effect<MemoryDeliveryImport, ThreadImportRejected | ThreadStoreError>;\n readonly peerCount: (threadId: ThreadId, nowMillis: number, limit: number) => number;\n}\n\n/** Native control metadata only; callers already hold the journal's shared gate. */\nexport interface MemoryWorkOwner {\n readonly page: (\n threadId: ThreadId,\n after: string | undefined,\n limit: number,\n ) => Effect.Effect<\n {\n readonly entries: ReadonlyArray<ThreadWorkEntry>;\n readonly after?: string;\n },\n ThreadStoreError\n >;\n readonly threads: (\n request: WorkThreadsRequest,\n ) => Effect.Effect<WorkThreadsPage, ThreadStoreError>;\n}\n\n/** One journal's private mutation boundary, shared with its paired ledger and delivery store. */\nexport class MemoryThreadStoreKernel extends Context.Service<\n MemoryThreadStoreKernel,\n {\n readonly owner: StorageOwner[\"Service\"];\n readonly withMutation: <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>;\n readonly registerWorkOwner: (\n kind: \"admissions\" | \"deliveries\",\n owner: MemoryWorkOwner,\n ) => Effect.Effect<void>;\n readonly registerDeliveryLookup: (\n exists: (threadId: ThreadId, messageId: IdempotencyKey) => boolean,\n ) => Effect.Effect<void>;\n /** Synchronous publication with the authoritative retained row, including replay membership. */\n readonly checkThreadCapacity: (threadId: ThreadId) => Effect.Effect<void, ThreadStoreError>;\n readonly initializeWork: (threadId: ThreadId) => void;\n readonly retainDelivery: (threadId: ThreadId, messageId: IdempotencyKey) => void;\n readonly registerLedgerTransfer: (transfer: MemoryLedgerTransfer) => Effect.Effect<void>;\n readonly registerDeliveryTransfer: (transfer: MemoryDeliveryTransfer) => Effect.Effect<void>;\n readonly prepareAppend: (\n request: AppendRequest,\n ) => Effect.Effect<PreparedMemoryAppend, ThreadStoreFailure>;\n readonly appendPrepared: (\n prepared: PreparedMemoryAppend,\n ) => Effect.Effect<AppendResult, ThreadStoreFailure>;\n readonly record: (\n threadId: ThreadId,\n recordId: RecordId,\n ) => Effect.Effect<RecordEnvelope | undefined>;\n /** Bounded canonical outcomes for one call; caller holds the shared mutation gate. */\n readonly toolCallResults: (\n threadId: ThreadId,\n runId: RunId,\n toolCallId: ToolCallId,\n ) => Effect.Effect<ReadonlyArray<RecordEnvelope>>;\n readonly tail: (threadId: ThreadId) => Effect.Effect<ThreadTail, ThreadStoreFailure>;\n }\n>()(\"@effect-agent/storage-memory/internal/MemoryThreadStoreKernel\") {}\n","/** Keep only the lowest distinct metadata keys after a cursor while scanning resident indexes. */\nexport const boundedWorkSelection = <A>(\n limit: number,\n key: (value: A) => string,\n after?: string,\n) => {\n const values: Array<A> = [];\n\n return {\n values,\n add: (value: A) => {\n const candidate = key(value);\n\n if (after !== undefined && candidate <= after) return;\n let low = 0;\n let high = values.length;\n\n while (low < high) {\n const middle = Math.floor((low + high) / 2);\n\n if (key(values[middle]) < candidate) low = middle + 1;\n else high = middle;\n }\n if (low >= limit || (low < values.length && key(values[low]) === candidate)) return;\n if (values.length === limit) values.pop();\n values.splice(low, 0, value);\n },\n };\n};\n"],"mappings":";;;AAuHA,IAAa,0BAAb,cAA6C,QAAQ,QAoCnD,CAAC,CAAC,+DAA+D,CAAC,CAAC,CAAC;;;;AC1JtE,MAAa,wBACX,OACA,KACA,UACG;CACH,MAAM,SAAmB,CAAC;CAE1B,OAAO;EACL;EACA,MAAM,UAAa;GACjB,MAAM,YAAY,IAAI,KAAK;GAE3B,IAAI,UAAU,KAAA,KAAa,aAAa,OAAO;GAC/C,IAAI,MAAM;GACV,IAAI,OAAO,OAAO;GAElB,OAAO,MAAM,MAAM;IACjB,MAAM,SAAS,KAAK,OAAO,MAAM,QAAQ,CAAC;IAE1C,IAAI,IAAI,OAAO,OAAO,IAAI,WAAW,MAAM,SAAS;SAC/C,OAAO;GACd;GACA,IAAI,OAAO,SAAU,MAAM,OAAO,UAAU,IAAI,OAAO,IAAI,MAAM,WAAY;GAC7E,IAAI,OAAO,WAAW,OAAO,OAAO,IAAI;GACxC,OAAO,OAAO,KAAK,GAAG,KAAK;EAC7B;CACF;AACF"}
|
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name":"@yielded/agent-storage-memory","version":"0.1.0-beta.
|
|
1
|
+
{"name":"@yielded/agent-storage-memory","version":"0.1.0-beta.171","dependencies":{"@yielded/agent":"0.1.0-beta.171"},"devDependencies":{"@effect/platform-node":"4.0.3","@effect/vitest":"4.0.3","effect":"4.0.3","typescript":"7.0.2","vite":"npm:@voidzero-dev/vite-plus-core@1.1.0","vite-plus":"1.1.0","vitest":"5.0.3"},"peerDependencies":{"effect":"^4.0.3"},"exports":{".":{"types":"./dist/index.d.mts","default":"./dist/index.mjs"},"./memory-message-delivery-store":{"types":"./dist/MemoryMessageDeliveryStore.d.mts","default":"./dist/MemoryMessageDeliveryStore.mjs"},"./memory-schedule-store":{"types":"./dist/MemoryScheduleStore.d.mts","default":"./dist/MemoryScheduleStore.mjs"},"./memory-semantic-index":{"types":"./dist/MemorySemanticIndex.d.mts","default":"./dist/MemorySemanticIndex.mjs"},"./memory-submission-ledger":{"types":"./dist/MemorySubmissionLedger.d.mts","default":"./dist/MemorySubmissionLedger.mjs"},"./memory-subscription-store":{"types":"./dist/MemorySubscriptionStore.d.mts","default":"./dist/MemorySubscriptionStore.mjs"},"./memory-thread-store":{"types":"./dist/MemoryThreadStore.d.mts","default":"./dist/MemoryThreadStore.mjs"}},"description":"In-memory Thread store and submission ledger reference adapters for Effect Agent tests and conformance suites.","license":"MIT","repository":{"type":"git","url":"git+https://github.com/yielded-dev/agent.git","directory":"packages/storage-memory"},"files":["dist","src"],"type":"module","sideEffects":[],"publishConfig":{"access":"public"},"scripts":{"build":"vp pack","check":"tsc --noEmit -p tsconfig.json","test":"vp test --passWithNoTests"}}
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
messageDeliveryDeadline,
|
|
14
14
|
messageDeliveryKeyString,
|
|
15
15
|
messageDeliveryUsesCapacity,
|
|
16
|
+
peerMessageRetentionDeadline,
|
|
16
17
|
isWorkerUpdateDelivery,
|
|
17
18
|
messageDeliveryCapacity,
|
|
18
19
|
sameMessageDeliveryIdentity,
|
|
@@ -86,11 +87,27 @@ const removeKey = (keys: Array<string>, key: string) => {
|
|
|
86
87
|
if (keys[at] === key) keys.splice(at, 1);
|
|
87
88
|
};
|
|
88
89
|
|
|
90
|
+
/** First deadline after the request time; retained evidence also supports clock rollback. */
|
|
91
|
+
const deadlinePosition = (deadlines: ReadonlyArray<number>, nowMillis: number) => {
|
|
92
|
+
let low = 0;
|
|
93
|
+
let high = deadlines.length;
|
|
94
|
+
|
|
95
|
+
while (low < high) {
|
|
96
|
+
const mid = Math.floor((low + high) / 2);
|
|
97
|
+
|
|
98
|
+
if (deadlines[mid] <= nowMillis) low = mid + 1;
|
|
99
|
+
else high = mid;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return low;
|
|
103
|
+
};
|
|
104
|
+
|
|
89
105
|
const backend = () => ({
|
|
90
106
|
records: new Map<string, string>(),
|
|
91
107
|
work: new Map<string, ThreadWorkEntry>(),
|
|
92
108
|
ordered: new Map<string, Array<string>>(),
|
|
93
109
|
pending: new Map<ThreadId, Set<MessageDeliveryKey["messageId"]>>(),
|
|
110
|
+
retainedPeers: new Map<ThreadId, Array<number>>(),
|
|
94
111
|
counts: new Map<ThreadId, { retained: number; ordinary: number; update: number; peer: number }>(),
|
|
95
112
|
metadata: new Map<
|
|
96
113
|
string,
|
|
@@ -98,6 +115,7 @@ const backend = () => ({
|
|
|
98
115
|
update: boolean;
|
|
99
116
|
pending: boolean;
|
|
100
117
|
peer: boolean;
|
|
118
|
+
peerRetentionDeadline: number | null;
|
|
101
119
|
deadlineKey?: string;
|
|
102
120
|
importVisit?: "visiting" | "verified";
|
|
103
121
|
}
|
|
@@ -234,6 +252,19 @@ export const memoryMessageDeliveryStoreLayer = (
|
|
|
234
252
|
else counts.ordinary++;
|
|
235
253
|
if (peer) counts.peer++;
|
|
236
254
|
}
|
|
255
|
+
const retentionDeadline = peerMessageRetentionDeadline(record);
|
|
256
|
+
const previousDeadline = old?.peerRetentionDeadline ?? null;
|
|
257
|
+
|
|
258
|
+
if (previousDeadline !== retentionDeadline) {
|
|
259
|
+
let retained = current.retainedPeers.get(owner);
|
|
260
|
+
|
|
261
|
+
if (retained === undefined) current.retainedPeers.set(owner, (retained = []));
|
|
262
|
+
if (previousDeadline !== null)
|
|
263
|
+
retained.splice(deadlinePosition(retained, previousDeadline) - 1, 1);
|
|
264
|
+
if (retentionDeadline !== null)
|
|
265
|
+
retained.splice(deadlinePosition(retained, retentionDeadline), 0, retentionDeadline);
|
|
266
|
+
if (retained.length === 0) current.retainedPeers.delete(owner);
|
|
267
|
+
}
|
|
237
268
|
let owned = current.pending.get(owner);
|
|
238
269
|
|
|
239
270
|
if (owned === undefined) current.pending.set(owner, (owned = new Set()));
|
|
@@ -283,6 +314,7 @@ export const memoryMessageDeliveryStoreLayer = (
|
|
|
283
314
|
update,
|
|
284
315
|
pending,
|
|
285
316
|
peer,
|
|
317
|
+
peerRetentionDeadline: retentionDeadline,
|
|
286
318
|
...(deadlineKey === undefined ? {} : { deadlineKey }),
|
|
287
319
|
});
|
|
288
320
|
if (pending)
|
|
@@ -494,8 +526,17 @@ export const memoryMessageDeliveryStoreLayer = (
|
|
|
494
526
|
deliveries: counts?.retained ?? 0,
|
|
495
527
|
};
|
|
496
528
|
},
|
|
497
|
-
|
|
498
|
-
|
|
529
|
+
peerCount: (threadId, nowMillis, limit) => {
|
|
530
|
+
const current = MutableRef.get(state.ref);
|
|
531
|
+
const retained = current.retainedPeers.get(threadId) ?? [];
|
|
532
|
+
|
|
533
|
+
return Math.min(
|
|
534
|
+
(current.counts.get(threadId)?.peer ?? 0) +
|
|
535
|
+
retained.length -
|
|
536
|
+
deadlinePosition(retained, nowMillis),
|
|
537
|
+
limit,
|
|
538
|
+
);
|
|
539
|
+
},
|
|
499
540
|
facts: Effect.fnUntraced(function* (threadId, after) {
|
|
500
541
|
const current = MutableRef.get(state.ref);
|
|
501
542
|
const keys = current.ordered.get(ownerKey(threadId)) ?? [];
|