mrmainspring 0.1.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.
- package/LICENSE +21 -0
- package/README.md +47 -0
- package/dist/audit/service.d.ts +7 -0
- package/dist/audit/service.js +98 -0
- package/dist/audit/store.d.ts +7 -0
- package/dist/audit/store.js +37 -0
- package/dist/audit/supabase-store.d.ts +9 -0
- package/dist/audit/supabase-store.js +22 -0
- package/dist/audit/types.d.ts +31 -0
- package/dist/audit/types.js +1 -0
- package/dist/casper/anchorClient.d.ts +99 -0
- package/dist/casper/anchorClient.js +412 -0
- package/dist/config.d.ts +51 -0
- package/dist/config.js +215 -0
- package/dist/env-file.d.ts +1 -0
- package/dist/env-file.js +51 -0
- package/dist/grimoire/service.d.ts +13 -0
- package/dist/grimoire/service.js +199 -0
- package/dist/grimoire/store.d.ts +10 -0
- package/dist/grimoire/store.js +64 -0
- package/dist/grimoire/supabase-store.d.ts +13 -0
- package/dist/grimoire/supabase-store.js +50 -0
- package/dist/grimoire/types.d.ts +60 -0
- package/dist/grimoire/types.js +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +17 -0
- package/dist/mcp/auditTools.d.ts +3 -0
- package/dist/mcp/auditTools.js +13 -0
- package/dist/mcp/grimoireTools.d.ts +3 -0
- package/dist/mcp/grimoireTools.js +91 -0
- package/dist/mcp/jsonResult.d.ts +2 -0
- package/dist/mcp/jsonResult.js +10 -0
- package/dist/mcp/memoryTools.d.ts +3 -0
- package/dist/mcp/memoryTools.js +73 -0
- package/dist/mcp/paymentTools.d.ts +3 -0
- package/dist/mcp/paymentTools.js +33 -0
- package/dist/memory/canonical.d.ts +4 -0
- package/dist/memory/canonical.js +49 -0
- package/dist/memory/hash.d.ts +1 -0
- package/dist/memory/hash.js +4 -0
- package/dist/memory/service.d.ts +37 -0
- package/dist/memory/service.js +175 -0
- package/dist/memory/store.d.ts +8 -0
- package/dist/memory/store.js +49 -0
- package/dist/memory/supabase-store.d.ts +10 -0
- package/dist/memory/supabase-store.js +30 -0
- package/dist/memory/types.d.ts +56 -0
- package/dist/memory/types.js +7 -0
- package/dist/payments/service.d.ts +26 -0
- package/dist/payments/service.js +613 -0
- package/dist/payments/store.d.ts +10 -0
- package/dist/payments/store.js +64 -0
- package/dist/payments/supabase-store.d.ts +13 -0
- package/dist/payments/supabase-store.js +51 -0
- package/dist/payments/types.d.ts +101 -0
- package/dist/payments/types.js +1 -0
- package/dist/server.d.ts +5 -0
- package/dist/server.js +68 -0
- package/dist/storage/json-file-store.d.ts +17 -0
- package/dist/storage/json-file-store.js +87 -0
- package/dist/storage/store-factory.d.ts +12 -0
- package/dist/storage/store-factory.js +26 -0
- package/dist/storage/supabase-rest.d.ts +26 -0
- package/dist/storage/supabase-rest.js +85 -0
- package/dist/x402/client.d.ts +44 -0
- package/dist/x402/client.js +95 -0
- package/dist/x402/facilitator.d.ts +84 -0
- package/dist/x402/facilitator.js +800 -0
- package/dist/x402/readiness.d.ts +55 -0
- package/dist/x402/readiness.js +433 -0
- package/dist/x402/redaction.d.ts +1 -0
- package/dist/x402/redaction.js +30 -0
- package/dist/x402/resource.d.ts +69 -0
- package/dist/x402/resource.js +325 -0
- package/dist/x402/settlement.d.ts +176 -0
- package/dist/x402/settlement.js +1210 -0
- package/dist/x402/signer.d.ts +71 -0
- package/dist/x402/signer.js +616 -0
- package/package.json +61 -0
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { jsonResult } from "./jsonResult.js";
|
|
3
|
+
import { memoryTypes } from "../memory/types.js";
|
|
4
|
+
const memoryTypeSchema = z.enum(memoryTypes);
|
|
5
|
+
const jsonBodySchema = z.record(z.string(), z.unknown());
|
|
6
|
+
export function registerMemoryTools(server, memoryService) {
|
|
7
|
+
server.registerTool("memory.write", {
|
|
8
|
+
title: "Write Memory",
|
|
9
|
+
description: "Store a Mr Mainspring agent memory and compute its deterministic content hash.",
|
|
10
|
+
inputSchema: {
|
|
11
|
+
agent_id: z.string().min(1),
|
|
12
|
+
type: memoryTypeSchema,
|
|
13
|
+
body: jsonBodySchema,
|
|
14
|
+
source: jsonBodySchema.optional(),
|
|
15
|
+
anchor: z.boolean().optional(),
|
|
16
|
+
memory_id: z.string().min(1).optional(),
|
|
17
|
+
prev_anchor_hash: z.string().min(1).nullable().optional()
|
|
18
|
+
}
|
|
19
|
+
}, async (input) => {
|
|
20
|
+
const memory = await memoryService.write(input);
|
|
21
|
+
return jsonResult({
|
|
22
|
+
memory_id: memory.memory_id,
|
|
23
|
+
content_hash: memory.content_hash,
|
|
24
|
+
metadata_hash: memory.metadata_hash,
|
|
25
|
+
anchor_status: memory.anchor_status,
|
|
26
|
+
created_at: memory.created_at
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
server.registerTool("memory.read", {
|
|
30
|
+
title: "Read Memory",
|
|
31
|
+
description: "Read one stored Mr Mainspring memory by agent and memory id.",
|
|
32
|
+
inputSchema: {
|
|
33
|
+
agent_id: z.string().min(1),
|
|
34
|
+
memory_id: z.string().min(1)
|
|
35
|
+
}
|
|
36
|
+
}, async ({ agent_id, memory_id }) => {
|
|
37
|
+
const memory = await memoryService.read(agent_id, memory_id);
|
|
38
|
+
if (!memory) {
|
|
39
|
+
return jsonResult({
|
|
40
|
+
found: false,
|
|
41
|
+
agent_id,
|
|
42
|
+
memory_id
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
return jsonResult({
|
|
46
|
+
found: true,
|
|
47
|
+
memory
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
server.registerTool("memory.search", {
|
|
51
|
+
title: "Search Memory",
|
|
52
|
+
description: "Search stored Mr Mainspring memories for an agent.",
|
|
53
|
+
inputSchema: {
|
|
54
|
+
agent_id: z.string().min(1),
|
|
55
|
+
query: z.string().default(""),
|
|
56
|
+
limit: z.number().int().min(1).max(50).optional()
|
|
57
|
+
}
|
|
58
|
+
}, async ({ agent_id, query, limit }) => {
|
|
59
|
+
const result = await memoryService.search(agent_id, query, limit);
|
|
60
|
+
return jsonResult(result);
|
|
61
|
+
});
|
|
62
|
+
server.registerTool("memory.verify", {
|
|
63
|
+
title: "Verify Memory",
|
|
64
|
+
description: "Recompute a local memory hash and report whether it still matches the stored hash.",
|
|
65
|
+
inputSchema: {
|
|
66
|
+
agent_id: z.string().min(1),
|
|
67
|
+
memory_id: z.string().min(1)
|
|
68
|
+
}
|
|
69
|
+
}, async ({ agent_id, memory_id }) => {
|
|
70
|
+
const verification = await memoryService.verify(agent_id, memory_id);
|
|
71
|
+
return jsonResult(verification);
|
|
72
|
+
});
|
|
73
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { jsonResult } from "./jsonResult.js";
|
|
3
|
+
const nonEmptyStringSchema = z.string().trim().min(1);
|
|
4
|
+
const urlSchema = z.string().trim().url();
|
|
5
|
+
const decimalAmountSchema = z
|
|
6
|
+
.string()
|
|
7
|
+
.trim()
|
|
8
|
+
.regex(/^\d+(\.\d+)?$/, "Expected a non-negative decimal amount");
|
|
9
|
+
export function registerPaymentTools(server, paymentService) {
|
|
10
|
+
server.registerTool("payment.fetch", {
|
|
11
|
+
title: "x402 Payment Fetch",
|
|
12
|
+
description: "Create a durable x402 payment record after checking a Grimoire policy. With request_challenge=true, make the first x402 HTTP request, persist and approve 402 requirements, then either persist a disabled/failed receipt or, when real settlement is configured, retry the paid resource with PAYMENT-SIGNATURE and return verified settlement without exposing signed payloads.",
|
|
13
|
+
inputSchema: {
|
|
14
|
+
agent_id: nonEmptyStringSchema,
|
|
15
|
+
policy_id: nonEmptyStringSchema,
|
|
16
|
+
method: nonEmptyStringSchema.default("GET"),
|
|
17
|
+
url: urlSchema,
|
|
18
|
+
expected_amount: decimalAmountSchema.optional(),
|
|
19
|
+
idempotency_key: nonEmptyStringSchema.optional(),
|
|
20
|
+
request_challenge: z.boolean().optional().default(false)
|
|
21
|
+
}
|
|
22
|
+
}, async (input) => {
|
|
23
|
+
const result = await paymentService.fetch(input);
|
|
24
|
+
return jsonResult(result);
|
|
25
|
+
});
|
|
26
|
+
server.registerTool("payment.receipt", {
|
|
27
|
+
title: "Read Payment Receipt",
|
|
28
|
+
description: "Return the persisted Mr Mainspring payment intent and receipt metadata. Signed payloads and secrets are never returned.",
|
|
29
|
+
inputSchema: {
|
|
30
|
+
payment_id: nonEmptyStringSchema
|
|
31
|
+
}
|
|
32
|
+
}, async ({ payment_id }) => jsonResult(await paymentService.receipt(payment_id)));
|
|
33
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { JsonObject, JsonValue } from "./types.js";
|
|
2
|
+
export declare function toJsonValue(value: unknown, path?: string): JsonValue;
|
|
3
|
+
export declare function toJsonObject(value: unknown, path?: string): JsonObject;
|
|
4
|
+
export declare function canonicalizeJson(value: unknown): string;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
export function toJsonValue(value, path = "$") {
|
|
2
|
+
if (value === null || typeof value === "string" || typeof value === "boolean") {
|
|
3
|
+
return value;
|
|
4
|
+
}
|
|
5
|
+
if (typeof value === "number") {
|
|
6
|
+
if (!Number.isFinite(value)) {
|
|
7
|
+
throw new Error(`Non-finite number at ${path}`);
|
|
8
|
+
}
|
|
9
|
+
return value;
|
|
10
|
+
}
|
|
11
|
+
if (Array.isArray(value)) {
|
|
12
|
+
return value.map((item, index) => toJsonValue(item, `${path}[${index}]`));
|
|
13
|
+
}
|
|
14
|
+
if (typeof value === "object") {
|
|
15
|
+
const objectValue = value;
|
|
16
|
+
const output = {};
|
|
17
|
+
for (const [key, item] of Object.entries(objectValue)) {
|
|
18
|
+
if (item === undefined) {
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
output[key] = toJsonValue(item, `${path}.${key}`);
|
|
22
|
+
}
|
|
23
|
+
return output;
|
|
24
|
+
}
|
|
25
|
+
throw new Error(`Unsupported JSON value at ${path}`);
|
|
26
|
+
}
|
|
27
|
+
export function toJsonObject(value, path = "$") {
|
|
28
|
+
const json = toJsonValue(value, path);
|
|
29
|
+
if (json === null || Array.isArray(json) || typeof json !== "object") {
|
|
30
|
+
throw new Error(`Expected JSON object at ${path}`);
|
|
31
|
+
}
|
|
32
|
+
return json;
|
|
33
|
+
}
|
|
34
|
+
export function canonicalizeJson(value) {
|
|
35
|
+
return JSON.stringify(sortJsonValue(toJsonValue(value)));
|
|
36
|
+
}
|
|
37
|
+
function sortJsonValue(value) {
|
|
38
|
+
if (Array.isArray(value)) {
|
|
39
|
+
return value.map(sortJsonValue);
|
|
40
|
+
}
|
|
41
|
+
if (value !== null && typeof value === "object") {
|
|
42
|
+
const sorted = {};
|
|
43
|
+
for (const key of Object.keys(value).sort()) {
|
|
44
|
+
sorted[key] = sortJsonValue(value[key]);
|
|
45
|
+
}
|
|
46
|
+
return sorted;
|
|
47
|
+
}
|
|
48
|
+
return value;
|
|
49
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function sha256Hex(input: string): string;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { AuditService } from "../audit/service.js";
|
|
2
|
+
import { type CasperAnchorClient } from "../casper/anchorClient.js";
|
|
3
|
+
import type { MemorySearchResult, MemoryStore, StoredMemoryEntry, WriteMemoryInput } from "./types.js";
|
|
4
|
+
export declare class MemoryService {
|
|
5
|
+
private readonly store;
|
|
6
|
+
private readonly audit?;
|
|
7
|
+
private readonly anchorClient?;
|
|
8
|
+
constructor(store: MemoryStore, audit?: AuditService | undefined, anchorClient?: CasperAnchorClient | undefined);
|
|
9
|
+
write(input: WriteMemoryInput): Promise<StoredMemoryEntry>;
|
|
10
|
+
read(agentId: string, memoryId: string): Promise<StoredMemoryEntry | null>;
|
|
11
|
+
search(agentId: string, query: string, limit?: number): Promise<MemorySearchResult>;
|
|
12
|
+
verify(agentId: string, memoryId: string): Promise<{
|
|
13
|
+
valid: boolean;
|
|
14
|
+
reason: string;
|
|
15
|
+
agent_id: string;
|
|
16
|
+
memory_id: string;
|
|
17
|
+
local_valid?: undefined;
|
|
18
|
+
anchor_status?: undefined;
|
|
19
|
+
local_content_hash?: undefined;
|
|
20
|
+
stored_content_hash?: undefined;
|
|
21
|
+
onchain_content_hash?: undefined;
|
|
22
|
+
anchor_id?: undefined;
|
|
23
|
+
casper_transaction_hash?: undefined;
|
|
24
|
+
} | {
|
|
25
|
+
valid: boolean;
|
|
26
|
+
local_valid: boolean;
|
|
27
|
+
anchor_status: import("./types.js").AnchorStatus;
|
|
28
|
+
agent_id: string;
|
|
29
|
+
memory_id: string;
|
|
30
|
+
local_content_hash: string;
|
|
31
|
+
stored_content_hash: string;
|
|
32
|
+
onchain_content_hash: string | null;
|
|
33
|
+
anchor_id: string | null;
|
|
34
|
+
casper_transaction_hash: string | null;
|
|
35
|
+
reason?: undefined;
|
|
36
|
+
}>;
|
|
37
|
+
}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { createAnchorSubmission, createPendingAnchorResult } from "../casper/anchorClient.js";
|
|
3
|
+
import { canonicalizeJson, toJsonObject } from "./canonical.js";
|
|
4
|
+
import { sha256Hex } from "./hash.js";
|
|
5
|
+
const MEMORY_SCHEMA_VERSION = "sigil.memory.v1";
|
|
6
|
+
export class MemoryService {
|
|
7
|
+
store;
|
|
8
|
+
audit;
|
|
9
|
+
anchorClient;
|
|
10
|
+
constructor(store, audit, anchorClient) {
|
|
11
|
+
this.store = store;
|
|
12
|
+
this.audit = audit;
|
|
13
|
+
this.anchorClient = anchorClient;
|
|
14
|
+
}
|
|
15
|
+
async write(input) {
|
|
16
|
+
const memoryId = input.memory_id ?? createMemoryId();
|
|
17
|
+
const createdAt = new Date().toISOString();
|
|
18
|
+
const source = toJsonObject(input.source ?? {}, "source");
|
|
19
|
+
const body = toJsonObject(input.body, "body");
|
|
20
|
+
const envelope = {
|
|
21
|
+
schema_version: MEMORY_SCHEMA_VERSION,
|
|
22
|
+
agent_id: input.agent_id,
|
|
23
|
+
memory_id: memoryId,
|
|
24
|
+
type: input.type,
|
|
25
|
+
source,
|
|
26
|
+
body,
|
|
27
|
+
created_at: createdAt,
|
|
28
|
+
prev_anchor_hash: input.prev_anchor_hash ?? null
|
|
29
|
+
};
|
|
30
|
+
const canonicalJson = canonicalizeJson(envelope);
|
|
31
|
+
const contentHash = sha256Hex(canonicalJson);
|
|
32
|
+
const metadataHash = sha256Hex(canonicalizeJson({
|
|
33
|
+
agent_id: envelope.agent_id,
|
|
34
|
+
memory_id: envelope.memory_id,
|
|
35
|
+
type: envelope.type,
|
|
36
|
+
source: envelope.source,
|
|
37
|
+
created_at: envelope.created_at
|
|
38
|
+
}));
|
|
39
|
+
let anchorSubmission = null;
|
|
40
|
+
let anchorResult = null;
|
|
41
|
+
if (input.anchor) {
|
|
42
|
+
anchorSubmission = createAnchorSubmission({
|
|
43
|
+
agent_id: envelope.agent_id,
|
|
44
|
+
memory_id: envelope.memory_id,
|
|
45
|
+
content_hash: contentHash,
|
|
46
|
+
metadata_hash: metadataHash,
|
|
47
|
+
prev_anchor_hash: envelope.prev_anchor_hash
|
|
48
|
+
});
|
|
49
|
+
anchorResult = this.anchorClient
|
|
50
|
+
? await this.anchorClient.anchorMemory(anchorSubmission)
|
|
51
|
+
: createPendingAnchorResult(anchorSubmission, "casper_client_not_configured");
|
|
52
|
+
}
|
|
53
|
+
const entry = {
|
|
54
|
+
...envelope,
|
|
55
|
+
canonical_json: canonicalJson,
|
|
56
|
+
content_hash: contentHash,
|
|
57
|
+
metadata_hash: metadataHash,
|
|
58
|
+
anchor_status: anchorResult?.status ?? (input.anchor ? "pending" : "not_requested"),
|
|
59
|
+
anchor_id: anchorResult?.anchor_id ?? anchorSubmission?.anchor_id ?? null,
|
|
60
|
+
casper_transaction_hash: anchorResult?.casper_transaction_hash ?? null,
|
|
61
|
+
onchain_content_hash: anchorResult?.onchain_content_hash ?? null,
|
|
62
|
+
updated_at: createdAt
|
|
63
|
+
};
|
|
64
|
+
await this.store.save(entry);
|
|
65
|
+
await this.audit?.record({
|
|
66
|
+
agent_id: entry.agent_id,
|
|
67
|
+
event_type: "memory.created",
|
|
68
|
+
subject_type: "memory",
|
|
69
|
+
subject_id: entry.memory_id,
|
|
70
|
+
metadata: {
|
|
71
|
+
type: entry.type,
|
|
72
|
+
content_hash: entry.content_hash,
|
|
73
|
+
metadata_hash: entry.metadata_hash,
|
|
74
|
+
anchor_status: entry.anchor_status
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
return entry;
|
|
78
|
+
}
|
|
79
|
+
async read(agentId, memoryId) {
|
|
80
|
+
return this.store.get(agentId, memoryId);
|
|
81
|
+
}
|
|
82
|
+
async search(agentId, query, limit = 10) {
|
|
83
|
+
const normalizedQuery = query.trim().toLowerCase();
|
|
84
|
+
const entries = await this.store.list(agentId);
|
|
85
|
+
const results = entries
|
|
86
|
+
.filter((entry) => {
|
|
87
|
+
if (normalizedQuery.length === 0) {
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
90
|
+
return buildSearchText(entry).includes(normalizedQuery);
|
|
91
|
+
})
|
|
92
|
+
.slice(0, Math.max(1, Math.min(limit, 50)))
|
|
93
|
+
.map(toSummary);
|
|
94
|
+
return {
|
|
95
|
+
agent_id: agentId,
|
|
96
|
+
query,
|
|
97
|
+
count: results.length,
|
|
98
|
+
results
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
async verify(agentId, memoryId) {
|
|
102
|
+
const entry = await this.store.get(agentId, memoryId);
|
|
103
|
+
if (!entry) {
|
|
104
|
+
return {
|
|
105
|
+
valid: false,
|
|
106
|
+
reason: "memory_not_found",
|
|
107
|
+
agent_id: agentId,
|
|
108
|
+
memory_id: memoryId
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
const envelope = toEnvelope(entry);
|
|
112
|
+
const localContentHash = sha256Hex(canonicalizeJson(envelope));
|
|
113
|
+
const localValid = localContentHash === entry.content_hash;
|
|
114
|
+
await this.audit?.record({
|
|
115
|
+
agent_id: agentId,
|
|
116
|
+
event_type: localValid ? "memory.verify_succeeded" : "memory.verify_failed",
|
|
117
|
+
subject_type: "memory",
|
|
118
|
+
subject_id: memoryId,
|
|
119
|
+
severity: localValid ? "info" : "warn",
|
|
120
|
+
metadata: {
|
|
121
|
+
local_content_hash: localContentHash,
|
|
122
|
+
stored_content_hash: entry.content_hash,
|
|
123
|
+
anchor_status: entry.anchor_status
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
return {
|
|
127
|
+
valid: localValid,
|
|
128
|
+
local_valid: localValid,
|
|
129
|
+
anchor_status: entry.anchor_status,
|
|
130
|
+
agent_id: agentId,
|
|
131
|
+
memory_id: memoryId,
|
|
132
|
+
local_content_hash: localContentHash,
|
|
133
|
+
stored_content_hash: entry.content_hash,
|
|
134
|
+
onchain_content_hash: entry.onchain_content_hash ?? null,
|
|
135
|
+
anchor_id: entry.anchor_id ?? null,
|
|
136
|
+
casper_transaction_hash: entry.casper_transaction_hash ?? null
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
function createMemoryId() {
|
|
141
|
+
return `mem_${randomUUID().replaceAll("-", "")}`;
|
|
142
|
+
}
|
|
143
|
+
function buildSearchText(entry) {
|
|
144
|
+
return [
|
|
145
|
+
entry.memory_id,
|
|
146
|
+
entry.type,
|
|
147
|
+
JSON.stringify(entry.source),
|
|
148
|
+
JSON.stringify(entry.body),
|
|
149
|
+
entry.content_hash
|
|
150
|
+
]
|
|
151
|
+
.join(" ")
|
|
152
|
+
.toLowerCase();
|
|
153
|
+
}
|
|
154
|
+
function toSummary(entry) {
|
|
155
|
+
return {
|
|
156
|
+
memory_id: entry.memory_id,
|
|
157
|
+
type: entry.type,
|
|
158
|
+
content_hash: entry.content_hash,
|
|
159
|
+
anchor_status: entry.anchor_status,
|
|
160
|
+
created_at: entry.created_at,
|
|
161
|
+
source: entry.source
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
function toEnvelope(entry) {
|
|
165
|
+
return {
|
|
166
|
+
schema_version: entry.schema_version,
|
|
167
|
+
agent_id: entry.agent_id,
|
|
168
|
+
memory_id: entry.memory_id,
|
|
169
|
+
type: entry.type,
|
|
170
|
+
source: entry.source,
|
|
171
|
+
body: entry.body,
|
|
172
|
+
created_at: entry.created_at,
|
|
173
|
+
prev_anchor_hash: entry.prev_anchor_hash
|
|
174
|
+
};
|
|
175
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { MemoryStore, StoredMemoryEntry } from "./types.js";
|
|
2
|
+
export declare class FileMemoryStore implements MemoryStore {
|
|
3
|
+
private readonly store;
|
|
4
|
+
constructor(dataDir: string);
|
|
5
|
+
save(entry: StoredMemoryEntry): Promise<void>;
|
|
6
|
+
get(agentId: string, memoryId: string): Promise<StoredMemoryEntry | null>;
|
|
7
|
+
list(agentId: string): Promise<StoredMemoryEntry[]>;
|
|
8
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import { JsonFileStore } from "../storage/json-file-store.js";
|
|
3
|
+
export class FileMemoryStore {
|
|
4
|
+
store;
|
|
5
|
+
constructor(dataDir) {
|
|
6
|
+
this.store = new JsonFileStore({
|
|
7
|
+
filePath: join(dataDir, "memory.json"),
|
|
8
|
+
empty: emptyStore,
|
|
9
|
+
normalize: normalizeStore
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
async save(entry) {
|
|
13
|
+
await this.store.update((data) => {
|
|
14
|
+
const existingIndex = data.memories.findIndex((memory) => memory.agent_id === entry.agent_id && memory.memory_id === entry.memory_id);
|
|
15
|
+
if (existingIndex >= 0) {
|
|
16
|
+
data.memories[existingIndex] = entry;
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
data.memories.push(entry);
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
async get(agentId, memoryId) {
|
|
24
|
+
const data = await this.store.read();
|
|
25
|
+
return (data.memories.find((memory) => memory.agent_id === agentId && memory.memory_id === memoryId) ?? null);
|
|
26
|
+
}
|
|
27
|
+
async list(agentId) {
|
|
28
|
+
const data = await this.store.read();
|
|
29
|
+
return data.memories
|
|
30
|
+
.filter((memory) => memory.agent_id === agentId)
|
|
31
|
+
.sort((left, right) => right.created_at.localeCompare(left.created_at));
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
function emptyStore() {
|
|
35
|
+
return {
|
|
36
|
+
schema_version: "sigil.memory-store.v1",
|
|
37
|
+
memories: []
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
function normalizeStore(parsed) {
|
|
41
|
+
const data = asStoreObject(parsed);
|
|
42
|
+
return {
|
|
43
|
+
schema_version: "sigil.memory-store.v1",
|
|
44
|
+
memories: Array.isArray(data.memories) ? data.memories : []
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
function asStoreObject(parsed) {
|
|
48
|
+
return parsed && typeof parsed === "object" ? parsed : {};
|
|
49
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { SupabaseRestClient } from "../storage/supabase-rest.js";
|
|
2
|
+
import type { MemoryStore, StoredMemoryEntry } from "./types.js";
|
|
3
|
+
export declare class SupabaseMemoryStore implements MemoryStore {
|
|
4
|
+
private readonly client;
|
|
5
|
+
private readonly table;
|
|
6
|
+
constructor(client: SupabaseRestClient);
|
|
7
|
+
save(entry: StoredMemoryEntry): Promise<void>;
|
|
8
|
+
get(agentId: string, memoryId: string): Promise<StoredMemoryEntry | null>;
|
|
9
|
+
list(agentId: string): Promise<StoredMemoryEntry[]>;
|
|
10
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export class SupabaseMemoryStore {
|
|
2
|
+
client;
|
|
3
|
+
table;
|
|
4
|
+
constructor(client) {
|
|
5
|
+
this.client = client;
|
|
6
|
+
this.table = client.table("memories");
|
|
7
|
+
}
|
|
8
|
+
async save(entry) {
|
|
9
|
+
await this.client.upsert(this.table, {
|
|
10
|
+
agent_id: entry.agent_id,
|
|
11
|
+
memory_id: entry.memory_id,
|
|
12
|
+
created_at: entry.created_at,
|
|
13
|
+
updated_at: entry.updated_at,
|
|
14
|
+
record: entry
|
|
15
|
+
}, "agent_id,memory_id");
|
|
16
|
+
}
|
|
17
|
+
async get(agentId, memoryId) {
|
|
18
|
+
const [record] = await this.client.selectRecords(this.table, {
|
|
19
|
+
filters: { agent_id: agentId, memory_id: memoryId },
|
|
20
|
+
limit: 1
|
|
21
|
+
});
|
|
22
|
+
return record ?? null;
|
|
23
|
+
}
|
|
24
|
+
async list(agentId) {
|
|
25
|
+
return this.client.selectRecords(this.table, {
|
|
26
|
+
filters: { agent_id: agentId },
|
|
27
|
+
order: { column: "created_at" }
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
export type JsonPrimitive = string | number | boolean | null;
|
|
2
|
+
export type JsonValue = JsonPrimitive | JsonObject | JsonValue[];
|
|
3
|
+
export type JsonObject = {
|
|
4
|
+
[key: string]: JsonValue;
|
|
5
|
+
};
|
|
6
|
+
export declare const memoryTypes: readonly ["observation", "decision", "payment", "secret_usage", "system_event"];
|
|
7
|
+
export type MemoryType = (typeof memoryTypes)[number];
|
|
8
|
+
export type AnchorStatus = "not_requested" | "pending" | "anchored" | "failed";
|
|
9
|
+
export type MemoryEnvelope = {
|
|
10
|
+
schema_version: "sigil.memory.v1";
|
|
11
|
+
agent_id: string;
|
|
12
|
+
memory_id: string;
|
|
13
|
+
type: MemoryType;
|
|
14
|
+
source: JsonObject;
|
|
15
|
+
body: JsonObject;
|
|
16
|
+
created_at: string;
|
|
17
|
+
prev_anchor_hash: string | null;
|
|
18
|
+
};
|
|
19
|
+
export type StoredMemoryEntry = MemoryEnvelope & {
|
|
20
|
+
canonical_json: string;
|
|
21
|
+
content_hash: string;
|
|
22
|
+
metadata_hash: string;
|
|
23
|
+
anchor_status: AnchorStatus;
|
|
24
|
+
anchor_id: string | null;
|
|
25
|
+
casper_transaction_hash: string | null;
|
|
26
|
+
onchain_content_hash: string | null;
|
|
27
|
+
updated_at: string;
|
|
28
|
+
};
|
|
29
|
+
export type WriteMemoryInput = {
|
|
30
|
+
agent_id: string;
|
|
31
|
+
type: MemoryType;
|
|
32
|
+
body: unknown;
|
|
33
|
+
source?: unknown;
|
|
34
|
+
anchor?: boolean;
|
|
35
|
+
memory_id?: string;
|
|
36
|
+
prev_anchor_hash?: string | null;
|
|
37
|
+
};
|
|
38
|
+
export type MemorySummary = {
|
|
39
|
+
memory_id: string;
|
|
40
|
+
type: MemoryType;
|
|
41
|
+
content_hash: string;
|
|
42
|
+
anchor_status: AnchorStatus;
|
|
43
|
+
created_at: string;
|
|
44
|
+
source: JsonObject;
|
|
45
|
+
};
|
|
46
|
+
export type MemorySearchResult = {
|
|
47
|
+
agent_id: string;
|
|
48
|
+
query: string;
|
|
49
|
+
count: number;
|
|
50
|
+
results: MemorySummary[];
|
|
51
|
+
};
|
|
52
|
+
export type MemoryStore = {
|
|
53
|
+
save(entry: StoredMemoryEntry): Promise<void>;
|
|
54
|
+
get(agentId: string, memoryId: string): Promise<StoredMemoryEntry | null>;
|
|
55
|
+
list(agentId: string): Promise<StoredMemoryEntry[]>;
|
|
56
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { AuditService } from "../audit/service.js";
|
|
2
|
+
import type { GrimoireService } from "../grimoire/service.js";
|
|
3
|
+
import type { X402ChallengeRequest, X402ChallengeResult } from "../x402/client.js";
|
|
4
|
+
import type { X402SettlementProvider } from "../x402/settlement.js";
|
|
5
|
+
import type { PaymentFetchInput, PaymentFetchResult, PaymentReceiptResult, PaymentStore } from "./types.js";
|
|
6
|
+
type X402ChallengeRequester = {
|
|
7
|
+
requestChallenge(input: X402ChallengeRequest): Promise<X402ChallengeResult>;
|
|
8
|
+
};
|
|
9
|
+
export declare class PaymentService {
|
|
10
|
+
private readonly grimoireService;
|
|
11
|
+
private readonly store;
|
|
12
|
+
private readonly audit?;
|
|
13
|
+
private readonly challengeClient?;
|
|
14
|
+
private readonly settlementProvider?;
|
|
15
|
+
constructor(grimoireService: GrimoireService, store: PaymentStore, audit?: AuditService | undefined, challengeClient?: X402ChallengeRequester | undefined, settlementProvider?: X402SettlementProvider | undefined);
|
|
16
|
+
preflightFetch(input: PaymentFetchInput): Promise<PaymentFetchResult>;
|
|
17
|
+
fetch(input: PaymentFetchInput): Promise<PaymentFetchResult>;
|
|
18
|
+
receipt(paymentId: string): Promise<PaymentReceiptResult>;
|
|
19
|
+
private fetchChallenge;
|
|
20
|
+
private markSettlementUnavailable;
|
|
21
|
+
private settleApprovedRequirement;
|
|
22
|
+
private checkCurrentPeriodSpend;
|
|
23
|
+
private persistSettlementReceipt;
|
|
24
|
+
private resultFromIntent;
|
|
25
|
+
}
|
|
26
|
+
export {};
|