silo-agent 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/README.md +330 -0
  2. package/bin/silo.js +55 -0
  3. package/build/demo.d.ts +13 -0
  4. package/build/demo.js +91 -0
  5. package/build/demo.js.map +1 -0
  6. package/build/doctor.d.ts +13 -0
  7. package/build/doctor.js +108 -0
  8. package/build/doctor.js.map +1 -0
  9. package/build/index.d.ts +16 -0
  10. package/build/index.js +17 -0
  11. package/build/index.js.map +1 -0
  12. package/build/lib/agent-router.d.ts +110 -0
  13. package/build/lib/agent-router.js +197 -0
  14. package/build/lib/agent-router.js.map +1 -0
  15. package/build/lib/attestation.d.ts +64 -0
  16. package/build/lib/attestation.js +112 -0
  17. package/build/lib/attestation.js.map +1 -0
  18. package/build/lib/autonomy.d.ts +116 -0
  19. package/build/lib/autonomy.js +266 -0
  20. package/build/lib/autonomy.js.map +1 -0
  21. package/build/lib/crypto.d.ts +33 -0
  22. package/build/lib/crypto.js +63 -0
  23. package/build/lib/crypto.js.map +1 -0
  24. package/build/lib/heartbeat.d.ts +111 -0
  25. package/build/lib/heartbeat.js +256 -0
  26. package/build/lib/heartbeat.js.map +1 -0
  27. package/build/lib/memory-coordinator.d.ts +150 -0
  28. package/build/lib/memory-coordinator.js +249 -0
  29. package/build/lib/memory-coordinator.js.map +1 -0
  30. package/build/lib/memory-index.d.ts +83 -0
  31. package/build/lib/memory-index.js +209 -0
  32. package/build/lib/memory-index.js.map +1 -0
  33. package/build/lib/shared-memory.d.ts +165 -0
  34. package/build/lib/shared-memory.js +398 -0
  35. package/build/lib/shared-memory.js.map +1 -0
  36. package/build/lib/storage.d.ts +38 -0
  37. package/build/lib/storage.js +106 -0
  38. package/build/lib/storage.js.map +1 -0
  39. package/build/lib/vault.d.ts +71 -0
  40. package/build/lib/vault.js +119 -0
  41. package/build/lib/vault.js.map +1 -0
  42. package/build/mcp.d.ts +32 -0
  43. package/build/mcp.js +734 -0
  44. package/build/mcp.js.map +1 -0
  45. package/build/server.d.ts +1 -0
  46. package/build/server.js +370 -0
  47. package/build/server.js.map +1 -0
  48. package/build/tests/attestation.test.d.ts +1 -0
  49. package/build/tests/attestation.test.js +175 -0
  50. package/build/tests/attestation.test.js.map +1 -0
  51. package/build/tests/crypto.test.d.ts +1 -0
  52. package/build/tests/crypto.test.js +109 -0
  53. package/build/tests/crypto.test.js.map +1 -0
  54. package/build/verify-flow.d.ts +10 -0
  55. package/build/verify-flow.js +81 -0
  56. package/build/verify-flow.js.map +1 -0
  57. package/build/verify.d.ts +14 -0
  58. package/build/verify.js +77 -0
  59. package/build/verify.js.map +1 -0
  60. package/package.json +61 -0
@@ -0,0 +1,83 @@
1
+ /**
2
+ * SILO — Memory Index
3
+ *
4
+ * A searchable catalog of everything stored on 0G through SILO.
5
+ * Solves the "I have a root hash but what IS it?" problem.
6
+ *
7
+ * Every store/write operation registers an entry in the index with:
8
+ * - The root hash (the 0G address)
9
+ * - Human-readable label
10
+ * - Tags for categorization
11
+ * - The channel it belongs to (if any)
12
+ * - Who stored it and when
13
+ * - Content type and size
14
+ *
15
+ * Agents can then SEARCH the index by label, tag, channel, author,
16
+ * or time range — no need to know root hashes in advance.
17
+ *
18
+ * The index itself is periodically snapshotted to 0G for durability.
19
+ * On startup, agents can load a snapshot to rebuild their local index.
20
+ */
21
+ export interface IndexEntry {
22
+ rootHash: string;
23
+ label: string;
24
+ tags: string[];
25
+ channel: string | null;
26
+ authorId: string;
27
+ contentType: "data" | "shared_memory" | "attestation_trace" | "snapshot" | "agent_descriptor" | "fix_record" | "heartbeat";
28
+ size: number;
29
+ createdAt: number;
30
+ contentHash: string;
31
+ description?: string;
32
+ expiresAt?: number;
33
+ metadata?: Record<string, any>;
34
+ }
35
+ export interface SearchQuery {
36
+ label?: string;
37
+ tags?: string[];
38
+ channel?: string;
39
+ authorId?: string;
40
+ contentType?: IndexEntry["contentType"];
41
+ fromTime?: number;
42
+ toTime?: number;
43
+ limit?: number;
44
+ }
45
+ export interface IndexSnapshot {
46
+ snapshotAt: number;
47
+ entryCount: number;
48
+ entries: IndexEntry[];
49
+ schemaVersion: number;
50
+ }
51
+ export declare class MemoryIndex {
52
+ private entries;
53
+ private tagIndex;
54
+ private channelIndex;
55
+ private labelIndex;
56
+ private authorIndex;
57
+ /** Register a new entry in the index */
58
+ register(entry: IndexEntry): void;
59
+ /** Look up a single entry by root hash */
60
+ lookup(rootHash: string): IndexEntry | undefined;
61
+ /** Search the index with flexible query parameters */
62
+ search(query: SearchQuery): IndexEntry[];
63
+ /** Get all unique tags in the index */
64
+ allTags(): string[];
65
+ /** Get all entries for a specific channel, ordered by time */
66
+ channelEntries(channel: string): IndexEntry[];
67
+ /** Get summary statistics */
68
+ stats(): {
69
+ totalEntries: number;
70
+ uniqueTags: number;
71
+ uniqueChannels: number;
72
+ uniqueAuthors: number;
73
+ byContentType: Record<string, number>;
74
+ };
75
+ /** Export the full index as a snapshot (for persisting to 0G) */
76
+ exportSnapshot(): IndexSnapshot;
77
+ /** Import a snapshot (for restoring from 0G) */
78
+ importSnapshot(snapshot: IndexSnapshot): number;
79
+ /** Remove expired entries */
80
+ pruneExpired(): number;
81
+ private removeEntry;
82
+ get size(): number;
83
+ }
@@ -0,0 +1,209 @@
1
+ /**
2
+ * SILO — Memory Index
3
+ *
4
+ * A searchable catalog of everything stored on 0G through SILO.
5
+ * Solves the "I have a root hash but what IS it?" problem.
6
+ *
7
+ * Every store/write operation registers an entry in the index with:
8
+ * - The root hash (the 0G address)
9
+ * - Human-readable label
10
+ * - Tags for categorization
11
+ * - The channel it belongs to (if any)
12
+ * - Who stored it and when
13
+ * - Content type and size
14
+ *
15
+ * Agents can then SEARCH the index by label, tag, channel, author,
16
+ * or time range — no need to know root hashes in advance.
17
+ *
18
+ * The index itself is periodically snapshotted to 0G for durability.
19
+ * On startup, agents can load a snapshot to rebuild their local index.
20
+ */
21
+ export class MemoryIndex {
22
+ entries = new Map();
23
+ tagIndex = new Map();
24
+ channelIndex = new Map();
25
+ labelIndex = new Map();
26
+ authorIndex = new Map();
27
+ /** Register a new entry in the index */
28
+ register(entry) {
29
+ this.entries.set(entry.rootHash, entry);
30
+ for (const tag of entry.tags) {
31
+ if (!this.tagIndex.has(tag))
32
+ this.tagIndex.set(tag, new Set());
33
+ this.tagIndex.get(tag).add(entry.rootHash);
34
+ }
35
+ if (entry.channel) {
36
+ if (!this.channelIndex.has(entry.channel))
37
+ this.channelIndex.set(entry.channel, new Set());
38
+ this.channelIndex.get(entry.channel).add(entry.rootHash);
39
+ }
40
+ const labelLower = entry.label.toLowerCase();
41
+ if (!this.labelIndex.has(labelLower))
42
+ this.labelIndex.set(labelLower, new Set());
43
+ this.labelIndex.get(labelLower).add(entry.rootHash);
44
+ if (!this.authorIndex.has(entry.authorId))
45
+ this.authorIndex.set(entry.authorId, new Set());
46
+ this.authorIndex.get(entry.authorId).add(entry.rootHash);
47
+ }
48
+ /** Look up a single entry by root hash */
49
+ lookup(rootHash) {
50
+ return this.entries.get(rootHash);
51
+ }
52
+ /** Search the index with flexible query parameters */
53
+ search(query) {
54
+ let candidateHashes = null;
55
+ if (query.tags?.length) {
56
+ const tagSets = query.tags
57
+ .map(t => this.tagIndex.get(t))
58
+ .filter((s) => !!s);
59
+ if (tagSets.length > 0) {
60
+ candidateHashes = intersectSets(tagSets);
61
+ }
62
+ else {
63
+ return [];
64
+ }
65
+ }
66
+ if (query.channel) {
67
+ const channelSet = this.channelIndex.get(query.channel);
68
+ if (!channelSet)
69
+ return [];
70
+ candidateHashes = candidateHashes ? intersectSets([candidateHashes, channelSet]) : new Set(channelSet);
71
+ }
72
+ if (query.authorId) {
73
+ const authorSet = this.authorIndex.get(query.authorId);
74
+ if (!authorSet)
75
+ return [];
76
+ candidateHashes = candidateHashes ? intersectSets([candidateHashes, authorSet]) : new Set(authorSet);
77
+ }
78
+ if (query.label) {
79
+ const labelLower = query.label.toLowerCase();
80
+ const exactMatch = this.labelIndex.get(labelLower);
81
+ if (exactMatch) {
82
+ candidateHashes = candidateHashes ? intersectSets([candidateHashes, exactMatch]) : new Set(exactMatch);
83
+ }
84
+ else {
85
+ const fuzzyMatches = new Set();
86
+ for (const [label, hashes] of this.labelIndex) {
87
+ if (label.includes(labelLower)) {
88
+ for (const h of hashes)
89
+ fuzzyMatches.add(h);
90
+ }
91
+ }
92
+ if (fuzzyMatches.size === 0)
93
+ return [];
94
+ candidateHashes = candidateHashes ? intersectSets([candidateHashes, fuzzyMatches]) : fuzzyMatches;
95
+ }
96
+ }
97
+ let results;
98
+ if (candidateHashes) {
99
+ results = Array.from(candidateHashes)
100
+ .map(h => this.entries.get(h))
101
+ .filter((e) => !!e);
102
+ }
103
+ else {
104
+ results = Array.from(this.entries.values());
105
+ }
106
+ if (query.contentType) {
107
+ results = results.filter(e => e.contentType === query.contentType);
108
+ }
109
+ if (query.fromTime) {
110
+ results = results.filter(e => e.createdAt >= query.fromTime);
111
+ }
112
+ if (query.toTime) {
113
+ results = results.filter(e => e.createdAt <= query.toTime);
114
+ }
115
+ results.sort((a, b) => b.createdAt - a.createdAt);
116
+ const limit = query.limit ?? 50;
117
+ return results.slice(0, limit);
118
+ }
119
+ /** Get all unique tags in the index */
120
+ allTags() {
121
+ return Array.from(this.tagIndex.keys()).sort();
122
+ }
123
+ /** Get all entries for a specific channel, ordered by time */
124
+ channelEntries(channel) {
125
+ const hashes = this.channelIndex.get(channel);
126
+ if (!hashes)
127
+ return [];
128
+ return Array.from(hashes)
129
+ .map(h => this.entries.get(h))
130
+ .filter((e) => !!e)
131
+ .sort((a, b) => a.createdAt - b.createdAt);
132
+ }
133
+ /** Get summary statistics */
134
+ stats() {
135
+ const byContentType = {};
136
+ for (const entry of this.entries.values()) {
137
+ byContentType[entry.contentType] = (byContentType[entry.contentType] ?? 0) + 1;
138
+ }
139
+ return {
140
+ totalEntries: this.entries.size,
141
+ uniqueTags: this.tagIndex.size,
142
+ uniqueChannels: this.channelIndex.size,
143
+ uniqueAuthors: this.authorIndex.size,
144
+ byContentType,
145
+ };
146
+ }
147
+ /** Export the full index as a snapshot (for persisting to 0G) */
148
+ exportSnapshot() {
149
+ return {
150
+ snapshotAt: Date.now(),
151
+ entryCount: this.entries.size,
152
+ entries: Array.from(this.entries.values()),
153
+ schemaVersion: 1,
154
+ };
155
+ }
156
+ /** Import a snapshot (for restoring from 0G) */
157
+ importSnapshot(snapshot) {
158
+ let imported = 0;
159
+ for (const entry of snapshot.entries) {
160
+ if (!this.entries.has(entry.rootHash)) {
161
+ this.register(entry);
162
+ imported++;
163
+ }
164
+ }
165
+ return imported;
166
+ }
167
+ /** Remove expired entries */
168
+ pruneExpired() {
169
+ const now = Date.now();
170
+ let pruned = 0;
171
+ for (const [rootHash, entry] of this.entries) {
172
+ if (entry.expiresAt && entry.expiresAt <= now) {
173
+ this.removeEntry(rootHash);
174
+ pruned++;
175
+ }
176
+ }
177
+ return pruned;
178
+ }
179
+ removeEntry(rootHash) {
180
+ const entry = this.entries.get(rootHash);
181
+ if (!entry)
182
+ return;
183
+ this.entries.delete(rootHash);
184
+ for (const tag of entry.tags) {
185
+ this.tagIndex.get(tag)?.delete(rootHash);
186
+ }
187
+ if (entry.channel) {
188
+ this.channelIndex.get(entry.channel)?.delete(rootHash);
189
+ }
190
+ this.labelIndex.get(entry.label.toLowerCase())?.delete(rootHash);
191
+ this.authorIndex.get(entry.authorId)?.delete(rootHash);
192
+ }
193
+ get size() { return this.entries.size; }
194
+ }
195
+ function intersectSets(sets) {
196
+ if (sets.length === 0)
197
+ return new Set();
198
+ if (sets.length === 1)
199
+ return new Set(sets[0]);
200
+ const [smallest, ...rest] = [...sets].sort((a, b) => a.size - b.size);
201
+ const result = new Set();
202
+ for (const item of smallest) {
203
+ if (rest.every(s => s.has(item))) {
204
+ result.add(item);
205
+ }
206
+ }
207
+ return result;
208
+ }
209
+ //# sourceMappingURL=memory-index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory-index.js","sourceRoot":"","sources":["../../src/lib/memory-index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,165 @@
1
+ /**
2
+ * SILO — Shared Memory Bus
3
+ *
4
+ * Named channels backed by 0G Storage for real-time multi-agent communication.
5
+ *
6
+ * Design:
7
+ * - Each channel is a linked list of entries on 0G (each entry points to the previous via rootHash)
8
+ * - A coordinator layer provides channel locks and optimistic concurrency control
9
+ * - A memory index provides root hash discoverability (search by label, tag, channel, author)
10
+ * - Periodic snapshots persist the full channel state to 0G for crash recovery
11
+ * - Any agent can create, join, write to, or read from a channel
12
+ *
13
+ * Safe Write Protocol (when coordinator is attached):
14
+ * 1. acquireLock(channel) → lockToken
15
+ * 2. Read current head → {headRootHash, version}
16
+ * 3. Upload to 0G with prevRootHash = headRootHash
17
+ * 4. commitWrite(channel, newRootHash, version, lockToken)
18
+ * 5. Coordinator validates → updates head → releases lock → broadcasts
19
+ *
20
+ * Without coordinator, writes are best-effort (backward compatible with v1).
21
+ */
22
+ import { AgentVault } from "./vault.js";
23
+ import { MemoryCoordinator, type ConflictError, type LockError } from "./memory-coordinator.js";
24
+ import { MemoryIndex, type IndexEntry } from "./memory-index.js";
25
+ export interface MemoryEntry {
26
+ id: string;
27
+ channel: string;
28
+ authorId: string;
29
+ timestamp: number;
30
+ data: string;
31
+ rootHash: string;
32
+ prevRootHash: string | null;
33
+ contentHash: string;
34
+ version: number;
35
+ metadata?: Record<string, any>;
36
+ }
37
+ export interface ChannelManifest {
38
+ name: string;
39
+ createdAt: number;
40
+ createdBy: string;
41
+ headRootHash: string | null;
42
+ version: number;
43
+ entryCount: number;
44
+ subscribers: string[];
45
+ snapshotRootHash: string | null;
46
+ lastSnapshotAt: number | null;
47
+ schema?: ChannelSchema;
48
+ }
49
+ export interface ChannelSchema {
50
+ description: string;
51
+ contentType?: string;
52
+ tags?: string[];
53
+ writableBy?: string[];
54
+ }
55
+ export interface ChannelSubscription {
56
+ channel: string;
57
+ agentId: string;
58
+ callback: (entry: MemoryEntry) => void;
59
+ }
60
+ export interface SharedMemoryConfig {
61
+ snapshotThreshold: number;
62
+ useCoordinator: boolean;
63
+ maxWriteRetries: number;
64
+ }
65
+ export type WriteResult = {
66
+ ok: true;
67
+ entry: MemoryEntry;
68
+ } | {
69
+ ok: false;
70
+ error: ConflictError | LockError | {
71
+ code: "ERROR";
72
+ message: string;
73
+ };
74
+ };
75
+ export declare class SharedMemoryBus {
76
+ private vault;
77
+ private coordinator;
78
+ private index;
79
+ private channels;
80
+ private entries;
81
+ private subscriptions;
82
+ private config;
83
+ private agentId;
84
+ private onBroadcast?;
85
+ constructor(vault: AgentVault, config?: Partial<SharedMemoryConfig>);
86
+ /** Attach a coordinator for multi-agent safety (run on the API server) */
87
+ attachCoordinator(coordinator: MemoryCoordinator): void;
88
+ /** Get the memory index (for search, lookup, stats) */
89
+ getIndex(): MemoryIndex;
90
+ /** Get the coordinator (if attached) */
91
+ getCoordinator(): MemoryCoordinator | null;
92
+ /** Register a broadcast handler (e.g., Socket.IO emitter) for cross-process notifications */
93
+ setBroadcastHandler(handler: (channel: string, entry: MemoryEntry) => void): void;
94
+ /**
95
+ * Create a new named channel with optional schema.
96
+ * If the channel already exists, returns the existing manifest.
97
+ */
98
+ createChannel(name: string, schema?: ChannelSchema): ChannelManifest;
99
+ /** Subscribe to a channel. Callback fires on every new entry. */
100
+ subscribe(channel: string, callback: (entry: MemoryEntry) => void): ChannelSubscription;
101
+ /** Unsubscribe from a channel */
102
+ unsubscribe(subscription: ChannelSubscription): void;
103
+ /**
104
+ * Write data to a channel with coordination.
105
+ *
106
+ * When a coordinator is attached:
107
+ * 1. Acquires channel lock
108
+ * 2. Reads current head + version
109
+ * 3. Uploads to 0G with correct prevRootHash
110
+ * 4. Commits via coordinator (validates version)
111
+ * 5. Retries on conflict up to maxWriteRetries
112
+ *
113
+ * Without coordinator: best-effort write (v1 behavior).
114
+ */
115
+ write(channel: string, data: string, metadata?: Record<string, any>): Promise<MemoryEntry>;
116
+ /**
117
+ * Safe write with full coordination — locks, version checks, conflict retry.
118
+ */
119
+ private coordinatedWrite;
120
+ /** Best-effort write without coordination (backward compatible) */
121
+ private uncoordinatedWrite;
122
+ private registerInIndex;
123
+ private notifySubscribers;
124
+ /**
125
+ * Read the latest N entries from a channel (from local cache).
126
+ * For full history recovery from 0G, use `recoverChannel()`.
127
+ */
128
+ read(channel: string, limit?: number): MemoryEntry[];
129
+ /** Read a specific entry from 0G by its root hash */
130
+ readFromStorage(rootHash: string): Promise<{
131
+ data: string;
132
+ prevRootHash: string | null;
133
+ }>;
134
+ /**
135
+ * Search the memory index. Agents use this to discover root hashes
136
+ * without knowing them in advance.
137
+ */
138
+ search(query: {
139
+ label?: string;
140
+ tags?: string[];
141
+ channel?: string;
142
+ authorId?: string;
143
+ contentType?: IndexEntry["contentType"];
144
+ limit?: number;
145
+ }): IndexEntry[];
146
+ /** Look up what a specific root hash contains */
147
+ lookupRootHash(rootHash: string): IndexEntry | undefined;
148
+ /**
149
+ * Persist the full channel state as a snapshot on 0G.
150
+ */
151
+ snapshot(channel: string): Promise<string>;
152
+ /**
153
+ * Recover a channel by walking the linked list from a known head root hash.
154
+ */
155
+ recoverChannel(channel: string, headRootHash: string, maxDepth?: number): Promise<MemoryEntry[]>;
156
+ /**
157
+ * Ingest an entry from another agent (received via WebSocket broadcast).
158
+ * Keeps the local cache in sync without re-downloading from 0G.
159
+ */
160
+ ingestRemoteEntry(entry: MemoryEntry): void;
161
+ /** List all known channels */
162
+ listChannels(): ChannelManifest[];
163
+ /** Get a channel's manifest */
164
+ getChannel(name: string): ChannelManifest | undefined;
165
+ }