@forbocai/core 0.5.7 → 0.5.8
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/ans104-QFXL554Z.mjs +190 -0
- package/dist/chunk-M3F3ED7H.mjs +83 -0
- package/dist/index.d.mts +89 -284
- package/dist/index.d.ts +89 -284
- package/dist/index.js +313 -986
- package/dist/index.mjs +238 -760
- package/dist/soul-QXKV5H2R.mjs +20 -0
- package/package.json +2 -7
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import "./chunk-7P6ASYW6.mjs";
|
|
2
|
+
|
|
3
|
+
// src/ans104.ts
|
|
4
|
+
import base64url from "base64url";
|
|
5
|
+
import { Buffer } from "buffer";
|
|
6
|
+
import { constants, createHash, createSign } from "crypto";
|
|
7
|
+
import { jwkTopem } from "arweave/node/lib/crypto/pem";
|
|
8
|
+
var SIGNATURE_TYPE_ARWEAVE = 1;
|
|
9
|
+
var SIGNATURE_LENGTH = 512;
|
|
10
|
+
var OWNER_LENGTH = 512;
|
|
11
|
+
var MAX_TAG_BYTES = 4096;
|
|
12
|
+
var stringToBuffer = (value) => Buffer.from(value);
|
|
13
|
+
var concatBuffers = (buffers) => Buffer.concat(buffers);
|
|
14
|
+
var longToNByteArray = (bytes, long) => {
|
|
15
|
+
if (long < 0) throw new Error("Array is unsigned, cannot represent -ve numbers");
|
|
16
|
+
if (long > 2 ** (bytes * 8) - 1) throw new Error(`Number ${long} is too large for an array of ${bytes} bytes`);
|
|
17
|
+
const step = (index, currentLong, acc) => index >= bytes ? acc : step(index + 1, (currentLong - (currentLong & 255)) / 256, [...acc, currentLong & 255]);
|
|
18
|
+
return new Uint8Array(step(0, long, []));
|
|
19
|
+
};
|
|
20
|
+
var longTo8ByteArray = (long) => longToNByteArray(8, long);
|
|
21
|
+
var shortTo2ByteArray = (short) => longToNByteArray(2, short);
|
|
22
|
+
var createTap = (buf = Buffer.alloc(MAX_TAG_BYTES), pos = 0) => ({ buf, pos });
|
|
23
|
+
var writeLongStep = (buf, pos, val) => {
|
|
24
|
+
const byte = val & 127;
|
|
25
|
+
const nextVal = val >> 7;
|
|
26
|
+
if (nextVal !== 0) {
|
|
27
|
+
buf[pos] = byte | 128;
|
|
28
|
+
return writeLongStep(buf, pos + 1, nextVal);
|
|
29
|
+
} else {
|
|
30
|
+
buf[pos] = byte;
|
|
31
|
+
return pos + 1;
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
var writeLongLargeStep = (buf, pos, val) => {
|
|
35
|
+
const byte = val & 127;
|
|
36
|
+
const nextVal = val / 128;
|
|
37
|
+
if (nextVal >= 1) {
|
|
38
|
+
buf[pos] = byte | 128;
|
|
39
|
+
return writeLongLargeStep(buf, pos + 1, nextVal);
|
|
40
|
+
} else {
|
|
41
|
+
buf[pos] = byte;
|
|
42
|
+
return pos + 1;
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
var writeLong = (tap, n) => {
|
|
46
|
+
const newBuf = Buffer.from(tap.buf);
|
|
47
|
+
let newPos;
|
|
48
|
+
if (n >= -1073741824 && n < 1073741824) {
|
|
49
|
+
const m = n >= 0 ? n << 1 : ~n << 1 | 1;
|
|
50
|
+
newPos = writeLongStep(newBuf, tap.pos, m);
|
|
51
|
+
} else {
|
|
52
|
+
const f = n >= 0 ? n * 2 : -n * 2 - 1;
|
|
53
|
+
newPos = writeLongLargeStep(newBuf, tap.pos, f);
|
|
54
|
+
}
|
|
55
|
+
return { buf: newBuf, pos: newPos };
|
|
56
|
+
};
|
|
57
|
+
var writeString = (tap, s) => {
|
|
58
|
+
const len = Buffer.byteLength(s);
|
|
59
|
+
const t1 = writeLong(tap, len);
|
|
60
|
+
if (t1.pos + len > t1.buf.length) return t1;
|
|
61
|
+
const newBuf = Buffer.from(t1.buf);
|
|
62
|
+
newBuf.write(s, t1.pos, len, "utf8");
|
|
63
|
+
return { buf: newBuf, pos: t1.pos + len };
|
|
64
|
+
};
|
|
65
|
+
var writeTagsRecursive = (tap, tags, index) => {
|
|
66
|
+
if (index >= tags.length) return tap;
|
|
67
|
+
const tag = tags[index];
|
|
68
|
+
if (typeof tag?.name !== "string" || typeof tag?.value !== "string") {
|
|
69
|
+
throw new Error(`Invalid tag format for ${tag}, expected {name:string, value: string}`);
|
|
70
|
+
}
|
|
71
|
+
const t1 = writeString(tap, tag.name);
|
|
72
|
+
const t2 = writeString(t1, tag.value);
|
|
73
|
+
return writeTagsRecursive(t2, tags, index + 1);
|
|
74
|
+
};
|
|
75
|
+
var writeTags = (tap, tags) => {
|
|
76
|
+
if (!Array.isArray(tags)) throw new Error("input must be array");
|
|
77
|
+
const t1 = tags.length > 0 ? writeLong(tap, tags.length) : tap;
|
|
78
|
+
const t2 = tags.length > 0 ? writeTagsRecursive(t1, tags, 0) : t1;
|
|
79
|
+
return writeLong(t2, 0);
|
|
80
|
+
};
|
|
81
|
+
var tapToBuffer = (tap) => {
|
|
82
|
+
if (tap.pos > tap.buf.length) throw new Error(`Too many tag bytes (${tap.pos} > ${tap.buf.length})`);
|
|
83
|
+
const buffer = Buffer.alloc(tap.pos);
|
|
84
|
+
tap.buf.copy(buffer, 0, 0, tap.pos);
|
|
85
|
+
return buffer;
|
|
86
|
+
};
|
|
87
|
+
var serializeTags = (tags) => {
|
|
88
|
+
if (tags?.length === 0) return Buffer.allocUnsafe(0);
|
|
89
|
+
return tapToBuffer(writeTags(createTap(), tags));
|
|
90
|
+
};
|
|
91
|
+
var hash = (data, algorithm) => {
|
|
92
|
+
const algo = algorithm === "SHA-256" ? "sha256" : "sha384";
|
|
93
|
+
return createHash(algo).update(data).digest();
|
|
94
|
+
};
|
|
95
|
+
var deepHashChunks = async (chunks, acc) => {
|
|
96
|
+
if (chunks.length < 1) return acc;
|
|
97
|
+
const h = await deepHash(chunks[0]);
|
|
98
|
+
const hashPair = concatBuffers([acc, h]);
|
|
99
|
+
return deepHashChunks(chunks.slice(1), hash(hashPair, "SHA-384"));
|
|
100
|
+
};
|
|
101
|
+
var deepHash = async (data) => {
|
|
102
|
+
if (Array.isArray(data)) {
|
|
103
|
+
const tag2 = concatBuffers([stringToBuffer("list"), stringToBuffer(data.length.toString())]);
|
|
104
|
+
return deepHashChunks(data, hash(tag2, "SHA-384"));
|
|
105
|
+
}
|
|
106
|
+
const _data = data;
|
|
107
|
+
const tag = concatBuffers([stringToBuffer("blob"), stringToBuffer(_data.byteLength.toString())]);
|
|
108
|
+
const taggedHash = concatBuffers([hash(tag, "SHA-384"), hash(_data, "SHA-384")]);
|
|
109
|
+
return hash(taggedHash, "SHA-384");
|
|
110
|
+
};
|
|
111
|
+
var getSignatureData = (signatureType, rawOwner, rawTarget, rawAnchor, rawTags, rawData) => deepHash([
|
|
112
|
+
stringToBuffer("dataitem"),
|
|
113
|
+
stringToBuffer("1"),
|
|
114
|
+
stringToBuffer(signatureType.toString()),
|
|
115
|
+
rawOwner,
|
|
116
|
+
rawTarget,
|
|
117
|
+
rawAnchor,
|
|
118
|
+
rawTags,
|
|
119
|
+
rawData
|
|
120
|
+
]);
|
|
121
|
+
var signData = (pemKey, message) => createSign("sha256").update(message).sign({
|
|
122
|
+
key: pemKey,
|
|
123
|
+
padding: constants.RSA_PKCS1_PSS_PADDING
|
|
124
|
+
});
|
|
125
|
+
var getOwner = (jwk) => base64url.toBuffer(jwk.n);
|
|
126
|
+
var getPem = (jwk) => {
|
|
127
|
+
const pem = jwkTopem(jwk);
|
|
128
|
+
return typeof pem === "string" ? pem : pem.toString();
|
|
129
|
+
};
|
|
130
|
+
var assembleDataItem = (rawOwner, rawTarget, rawAnchor, rawTags, rawData, opts) => {
|
|
131
|
+
const targetLength = 1 + (rawTarget?.byteLength ?? 0);
|
|
132
|
+
const anchorLength = 1 + (rawAnchor?.byteLength ?? 0);
|
|
133
|
+
const tagsLength = 16 + (rawTags ? rawTags.byteLength : 0);
|
|
134
|
+
const dataLength = rawData.byteLength;
|
|
135
|
+
const length = 2 + SIGNATURE_LENGTH + OWNER_LENGTH + targetLength + anchorLength + tagsLength + dataLength;
|
|
136
|
+
const bytes = Buffer.alloc(length);
|
|
137
|
+
bytes.set(shortTo2ByteArray(SIGNATURE_TYPE_ARWEAVE), 0);
|
|
138
|
+
bytes.set(new Uint8Array(SIGNATURE_LENGTH).fill(0), 2);
|
|
139
|
+
bytes.set(rawOwner, 2 + SIGNATURE_LENGTH);
|
|
140
|
+
const position = 2 + SIGNATURE_LENGTH + OWNER_LENGTH;
|
|
141
|
+
bytes[position] = rawTarget.length > 0 ? 1 : 0;
|
|
142
|
+
if (rawTarget.length > 0) {
|
|
143
|
+
if (rawTarget.byteLength !== 32) throw new Error("Target must be 32 bytes");
|
|
144
|
+
bytes.set(rawTarget, position + 1);
|
|
145
|
+
}
|
|
146
|
+
const anchorStart = position + targetLength;
|
|
147
|
+
let tagsStart = anchorStart + 1;
|
|
148
|
+
bytes[anchorStart] = rawAnchor.length > 0 ? 1 : 0;
|
|
149
|
+
if (rawAnchor.length > 0) {
|
|
150
|
+
tagsStart += rawAnchor.byteLength;
|
|
151
|
+
if (rawAnchor.byteLength !== 32) throw new Error("Anchor must be 32 bytes");
|
|
152
|
+
bytes.set(rawAnchor, anchorStart + 1);
|
|
153
|
+
}
|
|
154
|
+
bytes.set(longTo8ByteArray(opts?.tags?.length ?? 0), tagsStart);
|
|
155
|
+
bytes.set(longTo8ByteArray(rawTags?.byteLength ?? 0), tagsStart + 8);
|
|
156
|
+
if (rawTags.length > 0) {
|
|
157
|
+
bytes.set(rawTags, tagsStart + 16);
|
|
158
|
+
}
|
|
159
|
+
const dataStart = tagsStart + tagsLength;
|
|
160
|
+
bytes.set(rawData, dataStart);
|
|
161
|
+
return bytes;
|
|
162
|
+
};
|
|
163
|
+
var createArweaveDataItem = async (data, jwk, opts) => {
|
|
164
|
+
const rawOwner = getOwner(jwk);
|
|
165
|
+
if (rawOwner.byteLength !== OWNER_LENGTH) {
|
|
166
|
+
throw new Error(`Owner must be ${OWNER_LENGTH} bytes, but was ${rawOwner.byteLength}`);
|
|
167
|
+
}
|
|
168
|
+
const rawTarget = opts?.target ? base64url.toBuffer(opts.target) : Buffer.alloc(0);
|
|
169
|
+
const rawAnchor = opts?.anchor ? Buffer.from(opts.anchor) : Buffer.alloc(0);
|
|
170
|
+
const rawTags = (opts?.tags?.length ?? 0) > 0 ? serializeTags(opts?.tags) : Buffer.alloc(0);
|
|
171
|
+
const rawData = typeof data === "string" ? Buffer.from(data) : Buffer.from(data);
|
|
172
|
+
const signatureData = await getSignatureData(
|
|
173
|
+
SIGNATURE_TYPE_ARWEAVE,
|
|
174
|
+
rawOwner,
|
|
175
|
+
rawTarget,
|
|
176
|
+
rawAnchor,
|
|
177
|
+
rawTags,
|
|
178
|
+
rawData
|
|
179
|
+
);
|
|
180
|
+
const signature = signData(getPem(jwk), signatureData);
|
|
181
|
+
const bytes = assembleDataItem(rawOwner, rawTarget, rawAnchor, rawTags, rawData, opts);
|
|
182
|
+
bytes.set(signature, 2);
|
|
183
|
+
return {
|
|
184
|
+
id: base64url.encode(hash(signature, "SHA-256")),
|
|
185
|
+
raw: bytes
|
|
186
|
+
};
|
|
187
|
+
};
|
|
188
|
+
export {
|
|
189
|
+
createArweaveDataItem
|
|
190
|
+
};
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
// src/soul.ts
|
|
2
|
+
var createSoul = (id, name, persona, state, memories = []) => ({
|
|
3
|
+
id,
|
|
4
|
+
version: "1.0.0",
|
|
5
|
+
name,
|
|
6
|
+
persona,
|
|
7
|
+
state: { ...state },
|
|
8
|
+
memories: [...memories]
|
|
9
|
+
});
|
|
10
|
+
var serializeSoul = (soul) => JSON.stringify(soul, null, 2);
|
|
11
|
+
var deserializeSoul = (json) => {
|
|
12
|
+
const parsed = JSON.parse(json);
|
|
13
|
+
if (!parsed.id || !parsed.persona || !parsed.state) {
|
|
14
|
+
throw new Error("Invalid Soul format: missing required fields");
|
|
15
|
+
}
|
|
16
|
+
return {
|
|
17
|
+
id: parsed.id,
|
|
18
|
+
version: parsed.version || "1.0.0",
|
|
19
|
+
name: parsed.name || "Unknown",
|
|
20
|
+
persona: parsed.persona,
|
|
21
|
+
state: parsed.state,
|
|
22
|
+
memories: parsed.memories || [],
|
|
23
|
+
signature: parsed.signature
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
var exportSoul = async (agentId, _soul, config = {}) => {
|
|
27
|
+
const apiUrl = config.apiUrl || "https://api.forboc.ai";
|
|
28
|
+
const response = await fetch(`${apiUrl}/agents/${agentId}/soul/export`, {
|
|
29
|
+
method: "POST",
|
|
30
|
+
headers: { "Content-Type": "application/json" },
|
|
31
|
+
body: JSON.stringify({})
|
|
32
|
+
// Future: allow specifying memories to include
|
|
33
|
+
});
|
|
34
|
+
if (!response.ok) {
|
|
35
|
+
throw new Error(`Soul export failed: ${response.statusText}`);
|
|
36
|
+
}
|
|
37
|
+
const data = await response.json();
|
|
38
|
+
return {
|
|
39
|
+
txId: data.txId,
|
|
40
|
+
url: data.url,
|
|
41
|
+
soul: _soul
|
|
42
|
+
// Return the local soul data as context
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
var importSoulFromArweave = async (txId, config = {}) => {
|
|
46
|
+
const apiUrl = config.apiUrl || "https://api.forboc.ai";
|
|
47
|
+
const response = await fetch(`${apiUrl}/souls/${txId}`);
|
|
48
|
+
if (!response.ok) throw new Error(`Import failed: ${response.statusText}`);
|
|
49
|
+
const data = await response.json();
|
|
50
|
+
return data;
|
|
51
|
+
};
|
|
52
|
+
var getSoulList = async (limit = 50, apiUrl = "https://api.forboc.ai") => {
|
|
53
|
+
const response = await fetch(`${apiUrl}/souls?limit=${limit}`);
|
|
54
|
+
if (!response.ok) return [];
|
|
55
|
+
const data = await response.json();
|
|
56
|
+
return data.souls || [];
|
|
57
|
+
};
|
|
58
|
+
var createSoulInstance = (id, name, persona, state, memories = []) => {
|
|
59
|
+
const soulData = createSoul(id, name, persona, state, memories);
|
|
60
|
+
return {
|
|
61
|
+
export: (config) => exportSoul(id, soulData, config),
|
|
62
|
+
toJSON: () => ({ ...soulData })
|
|
63
|
+
};
|
|
64
|
+
};
|
|
65
|
+
var validateSoul = (soul) => {
|
|
66
|
+
const errors = [
|
|
67
|
+
!soul.id && "Missing id",
|
|
68
|
+
!soul.persona && "Missing persona",
|
|
69
|
+
!soul.state && "Missing state"
|
|
70
|
+
].filter((e) => !!e);
|
|
71
|
+
return { valid: errors.length === 0, errors };
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
export {
|
|
75
|
+
createSoul,
|
|
76
|
+
serializeSoul,
|
|
77
|
+
deserializeSoul,
|
|
78
|
+
exportSoul,
|
|
79
|
+
importSoulFromArweave,
|
|
80
|
+
getSoulList,
|
|
81
|
+
createSoulInstance,
|
|
82
|
+
validateSoul
|
|
83
|
+
};
|