@yielded/agent-storage-memory 0.1.0-beta.166 → 0.1.0-beta.168

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.
@@ -0,0 +1,156 @@
1
+ import type { RunId, SubmissionId, ThreadId, ToolCallId } from "@yielded/agent/identifiers";
2
+ import type { IdempotencyKey } from "@yielded/agent/receipt";
3
+ import type { RecordEnvelope, RecordId } from "@yielded/agent/records";
4
+ import type { StorageOwner } from "@yielded/agent/run-storage";
5
+ import type { SubmissionSnapshot, WorkerLedgerState } from "@yielded/agent/submission-ledger";
6
+ import type {
7
+ PreparedImportPage,
8
+ ThreadImportReader,
9
+ ThreadDeliveryImportReader,
10
+ ThreadImportRejected,
11
+ } from "@yielded/agent/thread-import";
12
+ import type {
13
+ AppendResult,
14
+ AppendRequest,
15
+ ThreadStoreFailure,
16
+ ThreadTail,
17
+ ThreadAdmission,
18
+ ThreadStoreError,
19
+ ThreadExportSnapshot,
20
+ } from "@yielded/agent/thread-store";
21
+ import type { TransferFacts, TransferSection } from "@yielded/agent/thread-transfer";
22
+ import type {
23
+ ThreadWorkEntry,
24
+ WorkThreadsRequest,
25
+ WorkThreadsPage,
26
+ } from "@yielded/agent/thread-work";
27
+ import { Context, type Effect, type Stream } from "effect";
28
+
29
+ export interface PreparedMemoryAppend {
30
+ readonly request: AppendRequest;
31
+ readonly batchJson: string;
32
+ }
33
+
34
+ /** Private storage, not a whole-Thread preparation value. Publication callbacks never yield. */
35
+ export interface MemoryLedgerImport {
36
+ readonly reader: Pick<ThreadImportReader["Service"], "admission" | "runOwner" | "commands">;
37
+ readonly stage: (
38
+ page: PreparedImportPage,
39
+ ) => Effect.Effect<void, ThreadImportRejected | ThreadStoreError>;
40
+ readonly prepareCommit: (
41
+ workerSeal?: Pick<WorkerLedgerState, "terminal">,
42
+ ) => Effect.Effect<() => void, ThreadImportRejected | ThreadStoreError, ThreadImportReader>;
43
+ }
44
+
45
+ export interface MemoryLedgerTransfer {
46
+ readonly snapshot: (threadId: ThreadId) => Effect.Effect<
47
+ Omit<typeof ThreadExportSnapshot.Type, "deliveries"> & {
48
+ readonly idle: boolean;
49
+ readonly workerSeal?: Pick<WorkerLedgerState, "terminal">;
50
+ },
51
+ ThreadStoreError
52
+ >;
53
+ readonly facts: (
54
+ threadId: ThreadId,
55
+ section: Exclude<TransferSection, "deliveries">,
56
+ after: string | undefined,
57
+ ) => Effect.Effect<{ readonly facts: TransferFacts; readonly after: string }, ThreadStoreError>;
58
+ readonly startImport: (
59
+ threadId: ThreadId,
60
+ ) => Effect.Effect<MemoryLedgerImport, ThreadImportRejected | ThreadStoreError>;
61
+ readonly submissions: (threadId: ThreadId) => Stream.Stream<SubmissionSnapshot, ThreadStoreError>;
62
+ readonly admission: (
63
+ threadId: ThreadId,
64
+ submissionId: SubmissionId,
65
+ ) => Effect.Effect<ThreadAdmission | undefined, ThreadStoreError>;
66
+ readonly commands: ThreadImportReader["Service"]["commands"];
67
+ }
68
+
69
+ export interface MemoryDeliveryImport {
70
+ readonly record: ThreadImportReader["Service"]["delivery"];
71
+ readonly stage: (
72
+ page: PreparedImportPage,
73
+ ) => Effect.Effect<void, ThreadImportRejected | ThreadStoreError>;
74
+ readonly has: (messageId: IdempotencyKey) => boolean;
75
+ readonly prepareCommit: () => Effect.Effect<
76
+ () => void,
77
+ ThreadImportRejected | ThreadStoreError,
78
+ ThreadDeliveryImportReader
79
+ >;
80
+ }
81
+
82
+ export interface MemoryDeliveryTransfer {
83
+ readonly record: (
84
+ threadId: ThreadId,
85
+ messageId: IdempotencyKey,
86
+ ) => ReturnType<ThreadImportReader["Service"]["delivery"]>;
87
+ readonly snapshot: (threadId: ThreadId) => {
88
+ readonly idle: boolean;
89
+ readonly deliveries: number;
90
+ };
91
+ readonly facts: (
92
+ threadId: ThreadId,
93
+ after: string | undefined,
94
+ ) => Effect.Effect<{ readonly facts: TransferFacts; readonly after: string }, ThreadStoreError>;
95
+ readonly startImport: (
96
+ threadId: ThreadId,
97
+ ) => Effect.Effect<MemoryDeliveryImport, ThreadImportRejected | ThreadStoreError>;
98
+ readonly pendingPeerCount: (threadId: ThreadId, limit: number) => number;
99
+ }
100
+
101
+ /** Native control metadata only; callers already hold the journal's shared gate. */
102
+ export interface MemoryWorkOwner {
103
+ readonly page: (
104
+ threadId: ThreadId,
105
+ after: string | undefined,
106
+ limit: number,
107
+ ) => Effect.Effect<
108
+ {
109
+ readonly entries: ReadonlyArray<ThreadWorkEntry>;
110
+ readonly after?: string;
111
+ },
112
+ ThreadStoreError
113
+ >;
114
+ readonly threads: (
115
+ request: WorkThreadsRequest,
116
+ ) => Effect.Effect<WorkThreadsPage, ThreadStoreError>;
117
+ }
118
+
119
+ /** One journal's private mutation boundary, shared with its paired ledger and delivery store. */
120
+ export class MemoryThreadStoreKernel extends Context.Service<
121
+ MemoryThreadStoreKernel,
122
+ {
123
+ readonly owner: StorageOwner["Service"];
124
+ readonly withMutation: <A, E, R>(effect: Effect.Effect<A, E, R>) => Effect.Effect<A, E, R>;
125
+ readonly registerWorkOwner: (
126
+ kind: "admissions" | "deliveries",
127
+ owner: MemoryWorkOwner,
128
+ ) => Effect.Effect<void>;
129
+ readonly registerDeliveryLookup: (
130
+ exists: (threadId: ThreadId, messageId: IdempotencyKey) => boolean,
131
+ ) => Effect.Effect<void>;
132
+ /** Synchronous publication with the authoritative retained row, including replay membership. */
133
+ readonly checkThreadCapacity: (threadId: ThreadId) => Effect.Effect<void, ThreadStoreError>;
134
+ readonly initializeWork: (threadId: ThreadId) => void;
135
+ readonly retainDelivery: (threadId: ThreadId, messageId: IdempotencyKey) => void;
136
+ readonly registerLedgerTransfer: (transfer: MemoryLedgerTransfer) => Effect.Effect<void>;
137
+ readonly registerDeliveryTransfer: (transfer: MemoryDeliveryTransfer) => Effect.Effect<void>;
138
+ readonly prepareAppend: (
139
+ request: AppendRequest,
140
+ ) => Effect.Effect<PreparedMemoryAppend, ThreadStoreFailure>;
141
+ readonly appendPrepared: (
142
+ prepared: PreparedMemoryAppend,
143
+ ) => Effect.Effect<AppendResult, ThreadStoreFailure>;
144
+ readonly record: (
145
+ threadId: ThreadId,
146
+ recordId: RecordId,
147
+ ) => Effect.Effect<RecordEnvelope | undefined>;
148
+ /** Bounded canonical outcomes for one call; caller holds the shared mutation gate. */
149
+ readonly toolCallResults: (
150
+ threadId: ThreadId,
151
+ runId: RunId,
152
+ toolCallId: ToolCallId,
153
+ ) => Effect.Effect<ReadonlyArray<RecordEnvelope>>;
154
+ readonly tail: (threadId: ThreadId) => Effect.Effect<ThreadTail, ThreadStoreFailure>;
155
+ }
156
+ >()("@effect-agent/storage-memory/internal/MemoryThreadStoreKernel") {}
@@ -0,0 +1,29 @@
1
+ /** Keep only the lowest distinct metadata keys after a cursor while scanning resident indexes. */
2
+ export const boundedWorkSelection = <A>(
3
+ limit: number,
4
+ key: (value: A) => string,
5
+ after?: string,
6
+ ) => {
7
+ const values: Array<A> = [];
8
+
9
+ return {
10
+ values,
11
+ add: (value: A) => {
12
+ const candidate = key(value);
13
+
14
+ if (after !== undefined && candidate <= after) return;
15
+ let low = 0;
16
+ let high = values.length;
17
+
18
+ while (low < high) {
19
+ const middle = Math.floor((low + high) / 2);
20
+
21
+ if (key(values[middle]) < candidate) low = middle + 1;
22
+ else high = middle;
23
+ }
24
+ if (low >= limit || (low < values.length && key(values[low]) === candidate)) return;
25
+ if (values.length === limit) values.pop();
26
+ values.splice(low, 0, value);
27
+ },
28
+ };
29
+ };