@forbocai/core 0.5.6 → 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 +131 -259
- package/dist/index.d.ts +131 -259
- package/dist/index.js +341 -941
- package/dist/index.mjs +262 -715
- package/dist/soul-QXKV5H2R.mjs +20 -0
- package/package.json +2 -7
package/dist/index.js
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __create = Object.create;
|
|
3
2
|
var __defProp = Object.defineProperty;
|
|
4
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
7
5
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
6
|
var __esm = (fn, res) => function __init() {
|
|
9
7
|
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
@@ -20,243 +18,95 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
20
18
|
}
|
|
21
19
|
return to;
|
|
22
20
|
};
|
|
23
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
24
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
25
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
26
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
27
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
28
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
29
|
-
mod
|
|
30
|
-
));
|
|
31
21
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
32
22
|
|
|
33
|
-
// src/
|
|
34
|
-
var
|
|
35
|
-
__export(
|
|
36
|
-
|
|
23
|
+
// src/soul.ts
|
|
24
|
+
var soul_exports = {};
|
|
25
|
+
__export(soul_exports, {
|
|
26
|
+
createSoul: () => createSoul,
|
|
27
|
+
createSoulInstance: () => createSoulInstance,
|
|
28
|
+
deserializeSoul: () => deserializeSoul,
|
|
29
|
+
exportSoul: () => exportSoul,
|
|
30
|
+
getSoulList: () => getSoulList,
|
|
31
|
+
importSoulFromArweave: () => importSoulFromArweave,
|
|
32
|
+
serializeSoul: () => serializeSoul,
|
|
33
|
+
validateSoul: () => validateSoul
|
|
37
34
|
});
|
|
38
|
-
var
|
|
39
|
-
var
|
|
40
|
-
"src/
|
|
35
|
+
var createSoul, serializeSoul, deserializeSoul, exportSoul, importSoulFromArweave, getSoulList, createSoulInstance, validateSoul;
|
|
36
|
+
var init_soul = __esm({
|
|
37
|
+
"src/soul.ts"() {
|
|
41
38
|
"use strict";
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
if (long > 2 ** (bytes * 8) - 1) throw new Error(`Number ${long} is too large for an array of ${bytes} bytes`);
|
|
56
|
-
for (let index = 0; index < byteArray.length; index++) {
|
|
57
|
-
const byte = long & 255;
|
|
58
|
-
byteArray[index] = byte;
|
|
59
|
-
long = (long - byte) / 256;
|
|
60
|
-
}
|
|
61
|
-
return byteArray;
|
|
62
|
-
};
|
|
63
|
-
longTo8ByteArray = (long) => longToNByteArray(8, long);
|
|
64
|
-
shortTo2ByteArray = (short) => longToNByteArray(2, short);
|
|
65
|
-
AVSCTap = class {
|
|
66
|
-
constructor(buf = import_buffer.Buffer.alloc(MAX_TAG_BYTES), pos = 0) {
|
|
67
|
-
this.buf = buf;
|
|
68
|
-
this.pos = pos;
|
|
69
|
-
}
|
|
70
|
-
writeTags(tags) {
|
|
71
|
-
if (!Array.isArray(tags)) {
|
|
72
|
-
throw new Error("input must be array");
|
|
73
|
-
}
|
|
74
|
-
const n = tags.length;
|
|
75
|
-
if (n) {
|
|
76
|
-
this.writeLong(n);
|
|
77
|
-
for (let i = 0; i < n; i++) {
|
|
78
|
-
const tag = tags[i];
|
|
79
|
-
if (typeof tag?.name !== "string" || typeof tag?.value !== "string") {
|
|
80
|
-
throw new Error(`Invalid tag format for ${tag}, expected {name:string, value: string}`);
|
|
81
|
-
}
|
|
82
|
-
this.writeString(tag.name);
|
|
83
|
-
this.writeString(tag.value);
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
this.writeLong(0);
|
|
87
|
-
}
|
|
88
|
-
toBuffer() {
|
|
89
|
-
const buffer = import_buffer.Buffer.alloc(this.pos);
|
|
90
|
-
if (this.pos > this.buf.length) throw new Error(`Too many tag bytes (${this.pos} > ${this.buf.length})`);
|
|
91
|
-
this.buf.copy(buffer, 0, 0, this.pos);
|
|
92
|
-
return buffer;
|
|
93
|
-
}
|
|
94
|
-
writeLong(n) {
|
|
95
|
-
const buf = this.buf;
|
|
96
|
-
let f, m;
|
|
97
|
-
if (n >= -1073741824 && n < 1073741824) {
|
|
98
|
-
m = n >= 0 ? n << 1 : ~n << 1 | 1;
|
|
99
|
-
do {
|
|
100
|
-
buf[this.pos] = m & 127;
|
|
101
|
-
m >>= 7;
|
|
102
|
-
} while (m && (buf[this.pos++] |= 128));
|
|
103
|
-
} else {
|
|
104
|
-
f = n >= 0 ? n * 2 : -n * 2 - 1;
|
|
105
|
-
do {
|
|
106
|
-
buf[this.pos] = f & 127;
|
|
107
|
-
f /= 128;
|
|
108
|
-
} while (f >= 1 && (buf[this.pos++] |= 128));
|
|
109
|
-
}
|
|
110
|
-
this.pos++;
|
|
111
|
-
this.buf = buf;
|
|
112
|
-
}
|
|
113
|
-
writeString(s) {
|
|
114
|
-
const len = import_buffer.Buffer.byteLength(s);
|
|
115
|
-
const buf = this.buf;
|
|
116
|
-
this.writeLong(len);
|
|
117
|
-
let pos = this.pos;
|
|
118
|
-
this.pos += len;
|
|
119
|
-
if (this.pos > buf.length) {
|
|
120
|
-
return;
|
|
121
|
-
}
|
|
122
|
-
if (len > 64) {
|
|
123
|
-
this.buf.write(s, this.pos - len, len, "utf8");
|
|
124
|
-
} else {
|
|
125
|
-
let i, l, c1, c2;
|
|
126
|
-
for (i = 0, l = len; i < l; i++) {
|
|
127
|
-
c1 = s.charCodeAt(i);
|
|
128
|
-
if (c1 < 128) {
|
|
129
|
-
buf[pos++] = c1;
|
|
130
|
-
} else if (c1 < 2048) {
|
|
131
|
-
buf[pos++] = c1 >> 6 | 192;
|
|
132
|
-
buf[pos++] = c1 & 63 | 128;
|
|
133
|
-
} else if ((c1 & 64512) === 55296 && ((c2 = s.charCodeAt(i + 1)) & 64512) === 56320) {
|
|
134
|
-
c1 = 65536 + ((c1 & 1023) << 10) + (c2 & 1023);
|
|
135
|
-
i++;
|
|
136
|
-
buf[pos++] = c1 >> 18 | 240;
|
|
137
|
-
buf[pos++] = c1 >> 12 & 63 | 128;
|
|
138
|
-
buf[pos++] = c1 >> 6 & 63 | 128;
|
|
139
|
-
buf[pos++] = c1 & 63 | 128;
|
|
140
|
-
} else {
|
|
141
|
-
buf[pos++] = c1 >> 12 | 224;
|
|
142
|
-
buf[pos++] = c1 >> 6 & 63 | 128;
|
|
143
|
-
buf[pos++] = c1 & 63 | 128;
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
this.buf = buf;
|
|
148
|
-
}
|
|
149
|
-
};
|
|
150
|
-
serializeTags = (tags) => {
|
|
151
|
-
if (tags?.length === 0) {
|
|
152
|
-
return import_buffer.Buffer.allocUnsafe(0);
|
|
153
|
-
}
|
|
154
|
-
const tap = new AVSCTap();
|
|
155
|
-
tap.writeTags(tags);
|
|
156
|
-
return tap.toBuffer();
|
|
157
|
-
};
|
|
158
|
-
hash = (data, algorithm) => {
|
|
159
|
-
const algo = algorithm === "SHA-256" ? "sha256" : "sha384";
|
|
160
|
-
return (0, import_crypto.createHash)(algo).update(data).digest();
|
|
161
|
-
};
|
|
162
|
-
deepHash = async (data) => {
|
|
163
|
-
if (Array.isArray(data)) {
|
|
164
|
-
const tag2 = concatBuffers([stringToBuffer("list"), stringToBuffer(data.length.toString())]);
|
|
165
|
-
return deepHashChunks(data, hash(tag2, "SHA-384"));
|
|
166
|
-
}
|
|
167
|
-
const _data = data;
|
|
168
|
-
const tag = concatBuffers([stringToBuffer("blob"), stringToBuffer(_data.byteLength.toString())]);
|
|
169
|
-
const taggedHash = concatBuffers([hash(tag, "SHA-384"), hash(_data, "SHA-384")]);
|
|
170
|
-
return hash(taggedHash, "SHA-384");
|
|
171
|
-
};
|
|
172
|
-
deepHashChunks = async (chunks, acc) => {
|
|
173
|
-
if (chunks.length < 1) {
|
|
174
|
-
return acc;
|
|
39
|
+
createSoul = (id, name, persona, state, memories = []) => ({
|
|
40
|
+
id,
|
|
41
|
+
version: "1.0.0",
|
|
42
|
+
name,
|
|
43
|
+
persona,
|
|
44
|
+
state: { ...state },
|
|
45
|
+
memories: [...memories]
|
|
46
|
+
});
|
|
47
|
+
serializeSoul = (soul) => JSON.stringify(soul, null, 2);
|
|
48
|
+
deserializeSoul = (json) => {
|
|
49
|
+
const parsed = JSON.parse(json);
|
|
50
|
+
if (!parsed.id || !parsed.persona || !parsed.state) {
|
|
51
|
+
throw new Error("Invalid Soul format: missing required fields");
|
|
175
52
|
}
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
rawOwner,
|
|
186
|
-
rawTarget,
|
|
187
|
-
rawAnchor,
|
|
188
|
-
rawTags,
|
|
189
|
-
rawData
|
|
190
|
-
]);
|
|
53
|
+
return {
|
|
54
|
+
id: parsed.id,
|
|
55
|
+
version: parsed.version || "1.0.0",
|
|
56
|
+
name: parsed.name || "Unknown",
|
|
57
|
+
persona: parsed.persona,
|
|
58
|
+
state: parsed.state,
|
|
59
|
+
memories: parsed.memories || [],
|
|
60
|
+
signature: parsed.signature
|
|
61
|
+
};
|
|
191
62
|
};
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
63
|
+
exportSoul = async (agentId, _soul, config = {}) => {
|
|
64
|
+
const apiUrl = config.apiUrl || "https://api.forboc.ai";
|
|
65
|
+
const response = await fetch(`${apiUrl}/agents/${agentId}/soul/export`, {
|
|
66
|
+
method: "POST",
|
|
67
|
+
headers: { "Content-Type": "application/json" },
|
|
68
|
+
body: JSON.stringify({})
|
|
69
|
+
// Future: allow specifying memories to include
|
|
196
70
|
});
|
|
71
|
+
if (!response.ok) {
|
|
72
|
+
throw new Error(`Soul export failed: ${response.statusText}`);
|
|
73
|
+
}
|
|
74
|
+
const data = await response.json();
|
|
75
|
+
return {
|
|
76
|
+
txId: data.txId,
|
|
77
|
+
url: data.url,
|
|
78
|
+
soul: _soul
|
|
79
|
+
// Return the local soul data as context
|
|
80
|
+
};
|
|
197
81
|
};
|
|
198
|
-
|
|
199
|
-
|
|
82
|
+
importSoulFromArweave = async (txId, config = {}) => {
|
|
83
|
+
const apiUrl = config.apiUrl || "https://api.forboc.ai";
|
|
84
|
+
const response = await fetch(`${apiUrl}/souls/${txId}`);
|
|
85
|
+
if (!response.ok) throw new Error(`Import failed: ${response.statusText}`);
|
|
86
|
+
const data = await response.json();
|
|
87
|
+
return data;
|
|
200
88
|
};
|
|
201
|
-
|
|
202
|
-
const
|
|
203
|
-
|
|
89
|
+
getSoulList = async (limit = 50, apiUrl = "https://api.forboc.ai") => {
|
|
90
|
+
const response = await fetch(`${apiUrl}/souls?limit=${limit}`);
|
|
91
|
+
if (!response.ok) return [];
|
|
92
|
+
const data = await response.json();
|
|
93
|
+
return data.souls || [];
|
|
204
94
|
};
|
|
205
|
-
|
|
206
|
-
const
|
|
207
|
-
if (rawOwner.byteLength !== OWNER_LENGTH) {
|
|
208
|
-
throw new Error(`Owner must be ${OWNER_LENGTH} bytes, but was ${rawOwner.byteLength}`);
|
|
209
|
-
}
|
|
210
|
-
const rawTarget = opts?.target ? import_base64url.default.toBuffer(opts.target) : import_buffer.Buffer.alloc(0);
|
|
211
|
-
const rawAnchor = opts?.anchor ? import_buffer.Buffer.from(opts.anchor) : import_buffer.Buffer.alloc(0);
|
|
212
|
-
const rawTags = (opts?.tags?.length ?? 0) > 0 ? serializeTags(opts?.tags) : import_buffer.Buffer.alloc(0);
|
|
213
|
-
const rawData = typeof data === "string" ? import_buffer.Buffer.from(data) : import_buffer.Buffer.from(data);
|
|
214
|
-
const targetLength = 1 + (rawTarget?.byteLength ?? 0);
|
|
215
|
-
const anchorLength = 1 + (rawAnchor?.byteLength ?? 0);
|
|
216
|
-
const tagsLength = 16 + (rawTags ? rawTags.byteLength : 0);
|
|
217
|
-
const dataLength = rawData.byteLength;
|
|
218
|
-
const length = 2 + SIGNATURE_LENGTH + OWNER_LENGTH + targetLength + anchorLength + tagsLength + dataLength;
|
|
219
|
-
const bytes = import_buffer.Buffer.alloc(length);
|
|
220
|
-
bytes.set(shortTo2ByteArray(SIGNATURE_TYPE_ARWEAVE), 0);
|
|
221
|
-
bytes.set(new Uint8Array(SIGNATURE_LENGTH).fill(0), 2);
|
|
222
|
-
bytes.set(rawOwner, 2 + SIGNATURE_LENGTH);
|
|
223
|
-
const position = 2 + SIGNATURE_LENGTH + OWNER_LENGTH;
|
|
224
|
-
bytes[position] = rawTarget.length > 0 ? 1 : 0;
|
|
225
|
-
if (rawTarget.length > 0) {
|
|
226
|
-
if (rawTarget.byteLength !== 32) throw new Error("Target must be 32 bytes");
|
|
227
|
-
bytes.set(rawTarget, position + 1);
|
|
228
|
-
}
|
|
229
|
-
const anchorStart = position + targetLength;
|
|
230
|
-
let tagsStart = anchorStart + 1;
|
|
231
|
-
bytes[anchorStart] = rawAnchor.length > 0 ? 1 : 0;
|
|
232
|
-
if (rawAnchor.length > 0) {
|
|
233
|
-
tagsStart += rawAnchor.byteLength;
|
|
234
|
-
if (rawAnchor.byteLength !== 32) throw new Error("Anchor must be 32 bytes");
|
|
235
|
-
bytes.set(rawAnchor, anchorStart + 1);
|
|
236
|
-
}
|
|
237
|
-
bytes.set(longTo8ByteArray(opts?.tags?.length ?? 0), tagsStart);
|
|
238
|
-
bytes.set(longTo8ByteArray(rawTags?.byteLength ?? 0), tagsStart + 8);
|
|
239
|
-
if (rawTags.length > 0) {
|
|
240
|
-
bytes.set(rawTags, tagsStart + 16);
|
|
241
|
-
}
|
|
242
|
-
const dataStart = tagsStart + tagsLength;
|
|
243
|
-
bytes.set(rawData, dataStart);
|
|
244
|
-
const signatureData = await getSignatureData(
|
|
245
|
-
SIGNATURE_TYPE_ARWEAVE,
|
|
246
|
-
rawOwner,
|
|
247
|
-
rawTarget,
|
|
248
|
-
rawAnchor,
|
|
249
|
-
rawTags,
|
|
250
|
-
rawData
|
|
251
|
-
);
|
|
252
|
-
const signature = await signData(getPem(jwk), signatureData);
|
|
253
|
-
bytes.set(signature, 2);
|
|
254
|
-
const id = hash(signature, "SHA-256");
|
|
95
|
+
createSoulInstance = (id, name, persona, state, memories = []) => {
|
|
96
|
+
const soulData = createSoul(id, name, persona, state, memories);
|
|
255
97
|
return {
|
|
256
|
-
|
|
257
|
-
|
|
98
|
+
export: (config) => exportSoul(id, soulData, config),
|
|
99
|
+
toJSON: () => ({ ...soulData })
|
|
258
100
|
};
|
|
259
101
|
};
|
|
102
|
+
validateSoul = (soul) => {
|
|
103
|
+
const errors = [
|
|
104
|
+
!soul.id && "Missing id",
|
|
105
|
+
!soul.persona && "Missing persona",
|
|
106
|
+
!soul.state && "Missing state"
|
|
107
|
+
].filter((e) => !!e);
|
|
108
|
+
return { valid: errors.length === 0, errors };
|
|
109
|
+
};
|
|
260
110
|
}
|
|
261
111
|
});
|
|
262
112
|
|
|
@@ -271,6 +121,7 @@ __export(index_exports, {
|
|
|
271
121
|
createRemoteCortex: () => createRemoteCortex,
|
|
272
122
|
createSoul: () => createSoul,
|
|
273
123
|
createSoulInstance: () => createSoulInstance,
|
|
124
|
+
delay: () => delay,
|
|
274
125
|
deserializeSoul: () => deserializeSoul,
|
|
275
126
|
exportSoul: () => exportSoul,
|
|
276
127
|
exportToSoul: () => exportToSoul,
|
|
@@ -280,12 +131,18 @@ __export(index_exports, {
|
|
|
280
131
|
getGhostStatus: () => getGhostStatus,
|
|
281
132
|
getSoulList: () => getSoulList,
|
|
282
133
|
importSoulFromArweave: () => importSoulFromArweave,
|
|
283
|
-
|
|
134
|
+
loadPreset: () => loadPreset,
|
|
135
|
+
memoise: () => memoise,
|
|
136
|
+
memoiseAsync: () => memoiseAsync,
|
|
137
|
+
pipe: () => pipe,
|
|
284
138
|
serializeSoul: () => serializeSoul,
|
|
285
139
|
startGhostSession: () => startGhostSession,
|
|
286
140
|
stopGhostSession: () => stopGhostSession,
|
|
141
|
+
streamFromCortex: () => streamFromCortex,
|
|
142
|
+
streamFromCortexWithDelay: () => streamFromCortexWithDelay,
|
|
143
|
+
streamToCallback: () => streamToCallback,
|
|
144
|
+
streamToString: () => streamToString,
|
|
287
145
|
updateAgentState: () => updateAgentState,
|
|
288
|
-
uploadToArweave: () => uploadToArweave,
|
|
289
146
|
validateAction: () => validateAction,
|
|
290
147
|
validateSoul: () => validateSoul,
|
|
291
148
|
waitForGhostCompletion: () => waitForGhostCompletion
|
|
@@ -293,143 +150,114 @@ __export(index_exports, {
|
|
|
293
150
|
module.exports = __toCommonJS(index_exports);
|
|
294
151
|
|
|
295
152
|
// src/agent.ts
|
|
296
|
-
var createInitialState = (partial) => {
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
153
|
+
var createInitialState = (partial) => ({ ...partial });
|
|
154
|
+
var updateAgentState = (currentState, updates) => ({
|
|
155
|
+
...currentState,
|
|
156
|
+
...updates
|
|
157
|
+
});
|
|
158
|
+
var exportToSoul = (agentId, name, persona, state, memories) => ({
|
|
159
|
+
id: agentId,
|
|
160
|
+
version: "1.0.0",
|
|
161
|
+
name,
|
|
162
|
+
persona,
|
|
163
|
+
memories: [...memories],
|
|
164
|
+
state: { ...state }
|
|
165
|
+
});
|
|
166
|
+
var storeMemoriesRecursive = async (memory, instructions, index = 0) => {
|
|
167
|
+
if (index >= instructions.length) return;
|
|
168
|
+
const { text, type, importance } = instructions[index];
|
|
169
|
+
await memory.store(text, type, importance).catch((e) => console.warn("Memory store failed:", e));
|
|
170
|
+
return storeMemoriesRecursive(memory, instructions, index + 1);
|
|
314
171
|
};
|
|
315
172
|
var createAgent = (config) => {
|
|
316
|
-
let
|
|
173
|
+
let _state = createInitialState(config.initialState);
|
|
317
174
|
const cortex = config.cortex;
|
|
318
175
|
const apiUrl = config.apiUrl || "https://api.forboc.ai";
|
|
319
176
|
const agentId = config.id || "agent-" + Math.random().toString(36).substring(7);
|
|
320
|
-
const
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
state = newState;
|
|
177
|
+
const authHeaders = config.apiKey ? { "Content-Type": "application/json", "Authorization": `Bearer ${config.apiKey}` } : { "Content-Type": "application/json" };
|
|
178
|
+
const getState = () => ({ ..._state });
|
|
179
|
+
const setState = (newState) => {
|
|
180
|
+
_state = newState;
|
|
325
181
|
};
|
|
326
182
|
const process = async (input, context = {}) => {
|
|
327
|
-
const currentState =
|
|
328
|
-
const directiveBody = {
|
|
329
|
-
observation: input,
|
|
330
|
-
agentState: currentState,
|
|
331
|
-
context
|
|
332
|
-
};
|
|
183
|
+
const currentState = getState();
|
|
333
184
|
const dirRes = await fetch(`${apiUrl}/agents/${agentId}/directive`, {
|
|
334
185
|
method: "POST",
|
|
335
|
-
headers:
|
|
336
|
-
body: JSON.stringify(
|
|
186
|
+
headers: authHeaders,
|
|
187
|
+
body: JSON.stringify({ observation: input, agentState: currentState, context })
|
|
337
188
|
});
|
|
338
|
-
if (!dirRes.ok) {
|
|
339
|
-
throw new Error(`API Directive Error: ${dirRes.status}`);
|
|
340
|
-
}
|
|
189
|
+
if (!dirRes.ok) throw new Error(`API Directive Error: ${dirRes.status}`);
|
|
341
190
|
const directiveData = await dirRes.json();
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
directiveData.memoryRecall.limit,
|
|
348
|
-
directiveData.memoryRecall.threshold
|
|
349
|
-
);
|
|
350
|
-
recalledMemories = rawMemories.map((m) => ({
|
|
351
|
-
text: m.text,
|
|
352
|
-
type: m.type,
|
|
353
|
-
importance: m.importance,
|
|
354
|
-
similarity: void 0
|
|
355
|
-
}));
|
|
356
|
-
} catch (e) {
|
|
357
|
-
console.warn("Memory recall failed, continuing with empty memories:", e);
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
const contextBody = {
|
|
361
|
-
memories: recalledMemories,
|
|
362
|
-
observation: input,
|
|
363
|
-
agentState: currentState
|
|
364
|
-
};
|
|
191
|
+
const recalledMemories = config.memory && directiveData.memoryRecall ? await config.memory.recall(
|
|
192
|
+
directiveData.memoryRecall.query,
|
|
193
|
+
directiveData.memoryRecall.limit,
|
|
194
|
+
directiveData.memoryRecall.threshold
|
|
195
|
+
).then((mems) => mems.map((m) => ({ text: m.text, type: m.type, importance: m.importance, similarity: void 0 }))).catch(() => []) : [];
|
|
365
196
|
const ctxRes = await fetch(`${apiUrl}/agents/${agentId}/context`, {
|
|
366
197
|
method: "POST",
|
|
367
|
-
headers:
|
|
368
|
-
body: JSON.stringify(
|
|
198
|
+
headers: authHeaders,
|
|
199
|
+
body: JSON.stringify({ memories: recalledMemories, observation: input, agentState: currentState })
|
|
369
200
|
});
|
|
370
|
-
if (!ctxRes.ok) {
|
|
371
|
-
throw new Error(`API Context Error: ${ctxRes.status}`);
|
|
372
|
-
}
|
|
201
|
+
if (!ctxRes.ok) throw new Error(`API Context Error: ${ctxRes.status}`);
|
|
373
202
|
const contextData = await ctxRes.json();
|
|
374
203
|
const generatedText = await cortex.complete(contextData.prompt, {
|
|
375
204
|
maxTokens: contextData.constraints.maxTokens,
|
|
376
205
|
temperature: contextData.constraints.temperature,
|
|
377
206
|
stop: contextData.constraints.stop
|
|
378
207
|
});
|
|
379
|
-
const verdictBody = {
|
|
380
|
-
generatedOutput: generatedText,
|
|
381
|
-
observation: input,
|
|
382
|
-
agentState: currentState
|
|
383
|
-
};
|
|
384
208
|
const verRes = await fetch(`${apiUrl}/agents/${agentId}/verdict`, {
|
|
385
209
|
method: "POST",
|
|
386
|
-
headers:
|
|
387
|
-
body: JSON.stringify(
|
|
210
|
+
headers: authHeaders,
|
|
211
|
+
body: JSON.stringify({ generatedOutput: generatedText, observation: input, agentState: currentState })
|
|
388
212
|
});
|
|
389
|
-
if (!verRes.ok) {
|
|
390
|
-
throw new Error(`API Verdict Error: ${verRes.status}`);
|
|
391
|
-
}
|
|
213
|
+
if (!verRes.ok) throw new Error(`API Verdict Error: ${verRes.status}`);
|
|
392
214
|
const verdictData = await verRes.json();
|
|
393
215
|
if (!verdictData.valid) {
|
|
394
|
-
return {
|
|
395
|
-
dialogue: "... [Action Blocked by Protocol]",
|
|
396
|
-
action: { type: "BLOCKED", reason: "API Validation Failed" }
|
|
397
|
-
};
|
|
216
|
+
return { dialogue: "... [Blocked]", action: { type: "BLOCKED", reason: "Validation Failed" } };
|
|
398
217
|
}
|
|
399
|
-
if (config.memory &&
|
|
400
|
-
|
|
401
|
-
config.memory.store(instruction.text, instruction.type, instruction.importance).catch((e) => console.warn("Memory store failed:", e));
|
|
402
|
-
}
|
|
218
|
+
if (config.memory && verdictData.memoryStore) {
|
|
219
|
+
storeMemoriesRecursive(config.memory, verdictData.memoryStore);
|
|
403
220
|
}
|
|
404
|
-
if (verdictData.stateDelta
|
|
405
|
-
|
|
221
|
+
if (verdictData.stateDelta) {
|
|
222
|
+
setState(updateAgentState(_state, verdictData.stateDelta));
|
|
406
223
|
}
|
|
407
224
|
return {
|
|
408
225
|
dialogue: generatedText,
|
|
409
|
-
action: verdictData.action ? {
|
|
410
|
-
...verdictData.action,
|
|
411
|
-
signature: verdictData.signature
|
|
412
|
-
} : void 0,
|
|
226
|
+
action: verdictData.action ? { ...verdictData.action, signature: verdictData.signature } : void 0,
|
|
413
227
|
thought: generatedText
|
|
414
228
|
};
|
|
415
229
|
};
|
|
230
|
+
const speak = async (message, context = {}) => {
|
|
231
|
+
const res = await fetch(`${apiUrl}/agents/${agentId}/speak`, {
|
|
232
|
+
method: "POST",
|
|
233
|
+
headers: authHeaders,
|
|
234
|
+
body: JSON.stringify({ speakMessage: message, speakContext: context, speakAgentState: getState() })
|
|
235
|
+
});
|
|
236
|
+
if (!res.ok) throw new Error(`API Speak Error: ${res.status}`);
|
|
237
|
+
const data = await res.json();
|
|
238
|
+
if (data.speakHistory) setState(updateAgentState(_state, { conversationHistory: data.speakHistory }));
|
|
239
|
+
return data.speakReply;
|
|
240
|
+
};
|
|
241
|
+
const dialogue = async (message, context = []) => {
|
|
242
|
+
const res = await fetch(`${apiUrl}/agents/${agentId}/dialogue`, {
|
|
243
|
+
method: "POST",
|
|
244
|
+
headers: authHeaders,
|
|
245
|
+
body: JSON.stringify({ diagMessage: message, diagContext: context })
|
|
246
|
+
});
|
|
247
|
+
if (!res.ok) throw new Error(`API Dialogue Error: ${res.status}`);
|
|
248
|
+
const data = await res.json();
|
|
249
|
+
return data.diagReply;
|
|
250
|
+
};
|
|
416
251
|
const exportSoul2 = async () => {
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
try {
|
|
420
|
-
exportedMemories = await config.memory.export();
|
|
421
|
-
} catch (e) {
|
|
422
|
-
console.warn("Memory export failed, exporting with empty memories:", e);
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
return exportToSoul(agentId, "Agent", config.persona, state, exportedMemories);
|
|
252
|
+
const memories = config.memory ? await config.memory.export().catch(() => []) : [];
|
|
253
|
+
return exportToSoul(agentId, "Agent", config.persona, _state, memories);
|
|
426
254
|
};
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
export: exportSoul2
|
|
255
|
+
const exportSoulToArweave = async (soulConfig) => {
|
|
256
|
+
const soul = await exportSoul2();
|
|
257
|
+
const { exportSoul: exportFunc } = await Promise.resolve().then(() => (init_soul(), soul_exports));
|
|
258
|
+
return exportFunc(agentId, soul, { ...soulConfig, apiUrl });
|
|
432
259
|
};
|
|
260
|
+
return { process, speak, dialogue, reply: speak, getState, setState, export: exportSoul2, exportSoul: exportSoulToArweave };
|
|
433
261
|
};
|
|
434
262
|
var fromSoul = async (soul, cortex, memory) => {
|
|
435
263
|
const agent = createAgent({
|
|
@@ -439,412 +267,180 @@ var fromSoul = async (soul, cortex, memory) => {
|
|
|
439
267
|
persona: soul.persona,
|
|
440
268
|
initialState: soul.state
|
|
441
269
|
});
|
|
442
|
-
if (memory && soul.memories && soul.memories.length > 0
|
|
443
|
-
|
|
444
|
-
await memory.import(soul.memories);
|
|
445
|
-
} catch (e) {
|
|
446
|
-
console.warn("Memory hydration failed, continuing without memories:", e);
|
|
447
|
-
}
|
|
270
|
+
if (memory && soul.memories && soul.memories.length > 0) {
|
|
271
|
+
await memory.import(soul.memories).catch((e) => console.warn("Memory hydration failed:", e));
|
|
448
272
|
}
|
|
449
273
|
return agent;
|
|
450
274
|
};
|
|
451
275
|
|
|
452
276
|
// src/bridge.ts
|
|
453
277
|
var createBridge = (config = {}) => {
|
|
454
|
-
const
|
|
455
|
-
|
|
456
|
-
...config
|
|
457
|
-
};
|
|
458
|
-
const rules = /* @__PURE__ */ new Map();
|
|
459
|
-
if (config.customRules) {
|
|
460
|
-
config.customRules.forEach((rule) => rules.set(rule.id, rule));
|
|
461
|
-
}
|
|
462
|
-
const validateRemote = async (action) => {
|
|
463
|
-
const response = await fetch(`${effectiveConfig.apiUrl}/bridge/validate`, {
|
|
464
|
-
method: "POST",
|
|
465
|
-
headers: { "Content-Type": "application/json" },
|
|
466
|
-
body: JSON.stringify({
|
|
467
|
-
actionType: action.type,
|
|
468
|
-
payload: JSON.stringify(action.payload || {})
|
|
469
|
-
})
|
|
470
|
-
});
|
|
471
|
-
if (!response.ok) {
|
|
472
|
-
throw new Error(`API validation failed: ${response.statusText}`);
|
|
473
|
-
}
|
|
474
|
-
const data = await response.json();
|
|
475
|
-
return {
|
|
476
|
-
valid: data.valid,
|
|
477
|
-
reason: data.reason
|
|
478
|
-
};
|
|
479
|
-
};
|
|
278
|
+
const apiUrl = config.apiUrl || "https://api.forboc.ai";
|
|
279
|
+
const agentId = config.agentId;
|
|
480
280
|
const validate = async (action, context = {}) => {
|
|
481
|
-
const
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
if (!
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
reason: `Unknown action type '${action.type}' in strict mode`,
|
|
492
|
-
correctedAction: { ...action, type: "IDLE", reason: "Unknown action type" }
|
|
493
|
-
};
|
|
494
|
-
}
|
|
495
|
-
}
|
|
496
|
-
let currentAction = action;
|
|
497
|
-
for (const rule of applicableRules) {
|
|
498
|
-
const result = rule.validate(currentAction, context);
|
|
499
|
-
if (!result.valid) {
|
|
500
|
-
return result;
|
|
501
|
-
}
|
|
502
|
-
if (result.correctedAction) {
|
|
503
|
-
currentAction = result.correctedAction;
|
|
281
|
+
const endpoint = agentId ? `${apiUrl}/bridge/validate/${agentId}` : `${apiUrl}/bridge/validate`;
|
|
282
|
+
try {
|
|
283
|
+
const response = await fetch(endpoint, {
|
|
284
|
+
method: "POST",
|
|
285
|
+
headers: { "Content-Type": "application/json" },
|
|
286
|
+
body: JSON.stringify({ action, context })
|
|
287
|
+
});
|
|
288
|
+
if (!response.ok) {
|
|
289
|
+
const error = await response.text();
|
|
290
|
+
throw new Error(`Bridge validation failed: ${error}`);
|
|
504
291
|
}
|
|
292
|
+
const data = await response.json();
|
|
293
|
+
return data.brResult || data;
|
|
294
|
+
} catch (e) {
|
|
295
|
+
console.error("[Bridge] Validation error:", e);
|
|
296
|
+
return {
|
|
297
|
+
valid: false,
|
|
298
|
+
reason: `Network error reaching validation API: ${e instanceof Error ? e.message : String(e)}`
|
|
299
|
+
};
|
|
505
300
|
}
|
|
506
|
-
return {
|
|
507
|
-
valid: true,
|
|
508
|
-
correctedAction: currentAction !== action ? currentAction : void 0
|
|
509
|
-
};
|
|
510
|
-
};
|
|
511
|
-
const registerRule = (rule) => {
|
|
512
|
-
rules.set(rule.id, rule);
|
|
513
|
-
};
|
|
514
|
-
const listRules = () => {
|
|
515
|
-
return Array.from(rules.values());
|
|
516
301
|
};
|
|
517
|
-
const
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
validate,
|
|
522
|
-
registerRule,
|
|
523
|
-
listRules,
|
|
524
|
-
removeRule
|
|
302
|
+
const listRulesets = async () => {
|
|
303
|
+
const response = await fetch(`${apiUrl}/rules`);
|
|
304
|
+
if (!response.ok) return [];
|
|
305
|
+
return response.json();
|
|
525
306
|
};
|
|
307
|
+
return { validate, listRulesets };
|
|
526
308
|
};
|
|
527
|
-
var validateAction = (action,
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
309
|
+
var validateAction = async (action, context = {}, config = {}) => {
|
|
310
|
+
const bridge = createBridge(config);
|
|
311
|
+
return bridge.validate(action, context);
|
|
312
|
+
};
|
|
313
|
+
var loadPreset = async (presetName, apiUrl = "https://api.forboc.ai") => {
|
|
314
|
+
const response = await fetch(`${apiUrl}/rules/presets/${presetName}`, {
|
|
315
|
+
method: "POST"
|
|
316
|
+
});
|
|
317
|
+
if (!response.ok) {
|
|
318
|
+
throw new Error(`Failed to load preset '${presetName}': ${response.statusText}`);
|
|
535
319
|
}
|
|
536
|
-
return
|
|
320
|
+
return response.json();
|
|
537
321
|
};
|
|
538
322
|
|
|
539
|
-
// src/
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
323
|
+
// src/index.ts
|
|
324
|
+
init_soul();
|
|
325
|
+
|
|
326
|
+
// src/utils.ts
|
|
327
|
+
var delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
328
|
+
var pipe = (...fns) => (initialValue) => fns.reduce((acc, fn) => fn(acc), initialValue);
|
|
329
|
+
var memoiseAsync = (fn) => {
|
|
330
|
+
let cached = null;
|
|
331
|
+
let promise = null;
|
|
332
|
+
return () => {
|
|
333
|
+
if (cached) return Promise.resolve(cached);
|
|
334
|
+
if (promise) return promise;
|
|
335
|
+
promise = fn().then((value) => {
|
|
336
|
+
cached = value;
|
|
337
|
+
return value;
|
|
338
|
+
});
|
|
339
|
+
return promise;
|
|
548
340
|
};
|
|
549
341
|
};
|
|
550
|
-
var
|
|
551
|
-
|
|
342
|
+
var memoise = (fn) => {
|
|
343
|
+
let cached = null;
|
|
344
|
+
let initialized = false;
|
|
345
|
+
return () => {
|
|
346
|
+
if (initialized) return cached;
|
|
347
|
+
cached = fn();
|
|
348
|
+
initialized = true;
|
|
349
|
+
return cached;
|
|
350
|
+
};
|
|
552
351
|
};
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
352
|
+
|
|
353
|
+
// src/ghost.ts
|
|
354
|
+
var DEFAULT_API_URL = "https://api.forboc.ai";
|
|
355
|
+
var startGhostSession = async (config) => {
|
|
356
|
+
const apiUrl = config.apiUrl || DEFAULT_API_URL;
|
|
357
|
+
const response = await fetch(`${apiUrl}/ghost/run`, {
|
|
358
|
+
method: "POST",
|
|
359
|
+
headers: { "Content-Type": "application/json" },
|
|
360
|
+
body: JSON.stringify({
|
|
361
|
+
testSuite: config.testSuite,
|
|
362
|
+
duration: config.duration
|
|
363
|
+
})
|
|
364
|
+
});
|
|
365
|
+
if (!response.ok) throw new Error(`Failed to start Ghost: ${response.statusText}`);
|
|
366
|
+
const data = await response.json();
|
|
558
367
|
return {
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
name: parsed.name || "Unknown",
|
|
562
|
-
persona: parsed.persona,
|
|
563
|
-
state: parsed.state,
|
|
564
|
-
memories: parsed.memories || [],
|
|
565
|
-
signature: parsed.signature
|
|
368
|
+
sessionId: data.sessionId,
|
|
369
|
+
status: data.runStatus
|
|
566
370
|
};
|
|
567
371
|
};
|
|
568
|
-
var
|
|
569
|
-
const
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
createArweaveDataItem2 = imported.createArweaveDataItem;
|
|
577
|
-
} catch (e) {
|
|
578
|
-
throw new Error("Missing ANS-104 Arweave module. Rebuild the SDK to enable direct uploads.");
|
|
579
|
-
}
|
|
580
|
-
const jwk = typeof wallet === "string" ? JSON.parse(wallet) : wallet;
|
|
581
|
-
const dataToUpload = serializeSoul(soul);
|
|
582
|
-
const tags = [
|
|
583
|
-
{ name: "Content-Type", value: "application/json" },
|
|
584
|
-
{ name: "App-Name", value: "ForbocAI" },
|
|
585
|
-
{ name: "App-Version", value: "soul-1" }
|
|
586
|
-
];
|
|
587
|
-
const dataItem = await createArweaveDataItem2(dataToUpload, jwk, { tags });
|
|
588
|
-
const rawData = dataItem.raw;
|
|
589
|
-
if (!rawData) {
|
|
590
|
-
throw new Error("Failed to build ANS-104 data item");
|
|
591
|
-
}
|
|
592
|
-
const bundlerUrl = config.bundlerUrl || "https://upload.ardrive.io/v1/tx";
|
|
593
|
-
const gatewayUrl = config.gatewayUrl || "https://arweave.net";
|
|
594
|
-
try {
|
|
595
|
-
const response = await fetch(bundlerUrl, {
|
|
596
|
-
method: "POST",
|
|
597
|
-
headers: { "Content-Type": "application/octet-stream" },
|
|
598
|
-
body: rawData
|
|
599
|
-
});
|
|
600
|
-
if (!response.ok) {
|
|
601
|
-
const message = await response.text().catch(() => response.statusText);
|
|
602
|
-
throw new Error(message || response.statusText);
|
|
603
|
-
}
|
|
604
|
-
const responseText = await response.text();
|
|
605
|
-
let responseJson = null;
|
|
606
|
-
try {
|
|
607
|
-
responseJson = JSON.parse(responseText);
|
|
608
|
-
} catch {
|
|
609
|
-
responseJson = null;
|
|
610
|
-
}
|
|
611
|
-
const txId = responseJson?.id || responseJson?.dataItemId || responseJson?.txId || (typeof responseText === "string" && responseText.trim().length > 0 ? responseText.trim() : null) || dataItem.id;
|
|
612
|
-
if (!txId) {
|
|
613
|
-
throw new Error("Bundler response did not include a data item id");
|
|
614
|
-
}
|
|
615
|
-
return {
|
|
616
|
-
txId,
|
|
617
|
-
url: `${gatewayUrl}/${txId}`,
|
|
618
|
-
soul
|
|
619
|
-
};
|
|
620
|
-
} catch (e) {
|
|
621
|
-
throw new Error(`Failed to upload to Arweave: ${e}`);
|
|
622
|
-
}
|
|
623
|
-
};
|
|
624
|
-
var exportSoul = async (_agentId, soul, config = {}) => {
|
|
625
|
-
if (!config.walletJwk && !config.privateKey) {
|
|
626
|
-
throw new Error("walletJwk required for Arweave ANS-104 export");
|
|
627
|
-
}
|
|
628
|
-
return uploadToArweave(soul, config);
|
|
629
|
-
};
|
|
630
|
-
var importSoulFromArweave = async (txId, config = {}) => {
|
|
631
|
-
const gateway = config.gatewayUrl || "https://arweave.net";
|
|
632
|
-
try {
|
|
633
|
-
const response = await fetch(`${gateway}/${txId}`, {
|
|
634
|
-
method: "GET",
|
|
635
|
-
headers: { "Content-Type": "application/json" }
|
|
636
|
-
});
|
|
637
|
-
if (!response.ok) {
|
|
638
|
-
throw new Error(`Import failed: ${response.statusText}`);
|
|
639
|
-
}
|
|
640
|
-
const data = await response.json();
|
|
641
|
-
if (!data.id || !data.persona) {
|
|
642
|
-
throw new Error("Invalid soul data from Arweave");
|
|
643
|
-
}
|
|
644
|
-
return data;
|
|
645
|
-
} catch (e) {
|
|
646
|
-
throw new Error(`Failed to import Soul from TXID ${txId}: ${e}`);
|
|
647
|
-
}
|
|
648
|
-
};
|
|
649
|
-
var getSoulList = async (limit = 50, apiUrl) => {
|
|
650
|
-
const url = apiUrl || "https://api.forboc.ai";
|
|
651
|
-
try {
|
|
652
|
-
const response = await fetch(`${url}/souls?limit=${limit}`);
|
|
653
|
-
if (!response.ok) throw new Error(response.statusText);
|
|
654
|
-
const data = await response.json();
|
|
655
|
-
return data.souls.map((s) => {
|
|
656
|
-
const txId = s.txId || s.soulEntryTxId || s.cid;
|
|
657
|
-
const name = s.name || s.soulEntryName;
|
|
658
|
-
const agentId = s.agentId || s.soulEntryAgentId;
|
|
659
|
-
const exportedAt = s.exportedAt || s.soulEntryExportedAt;
|
|
660
|
-
const url2 = s.url || s.soulEntryArweaveUrl || `https://arweave.net/${txId}`;
|
|
661
|
-
return { txId, name, agentId, exportedAt, url: url2 };
|
|
662
|
-
});
|
|
663
|
-
} catch (e) {
|
|
664
|
-
return [];
|
|
665
|
-
}
|
|
666
|
-
};
|
|
667
|
-
var createSoulInstance = (id, name, persona, state, memories = []) => {
|
|
668
|
-
const soulData = createSoul(id, name, persona, state, memories);
|
|
669
|
-
const performExport = async (config) => {
|
|
670
|
-
return exportSoul(soulData.id, soulData, { ...config });
|
|
671
|
-
};
|
|
372
|
+
var getGhostStatus = async (sessionId, apiUrl) => {
|
|
373
|
+
const url = apiUrl || DEFAULT_API_URL;
|
|
374
|
+
const response = await fetch(`${url}/ghost/${sessionId}/status`, {
|
|
375
|
+
method: "GET",
|
|
376
|
+
headers: { "Content-Type": "application/json" }
|
|
377
|
+
});
|
|
378
|
+
if (!response.ok) throw new Error(`Failed to get status: ${response.statusText}`);
|
|
379
|
+
const data = await response.json();
|
|
672
380
|
return {
|
|
673
|
-
|
|
674
|
-
|
|
381
|
+
sessionId: data.ghostSessionId,
|
|
382
|
+
status: data.ghostStatus,
|
|
383
|
+
progress: data.ghostProgress,
|
|
384
|
+
startedAt: data.ghostStartedAt,
|
|
385
|
+
duration: data.ghostDuration,
|
|
386
|
+
errors: data.ghostErrors
|
|
675
387
|
};
|
|
676
388
|
};
|
|
677
|
-
var
|
|
678
|
-
const
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
389
|
+
var getGhostResults = async (sessionId, apiUrl) => {
|
|
390
|
+
const url = apiUrl || DEFAULT_API_URL;
|
|
391
|
+
const response = await fetch(`${url}/ghost/${sessionId}/results`, {
|
|
392
|
+
method: "GET",
|
|
393
|
+
headers: { "Content-Type": "application/json" }
|
|
394
|
+
});
|
|
395
|
+
if (!response.ok) throw new Error(`Failed to get results: ${response.statusText}`);
|
|
396
|
+
const data = await response.json();
|
|
682
397
|
return {
|
|
683
|
-
|
|
684
|
-
|
|
398
|
+
sessionId: data.resultsSessionId,
|
|
399
|
+
totalTests: data.resultsTotalTests,
|
|
400
|
+
passed: data.resultsPassed,
|
|
401
|
+
failed: data.resultsFailed,
|
|
402
|
+
skipped: data.resultsSkipped,
|
|
403
|
+
duration: data.resultsDuration,
|
|
404
|
+
tests: data.resultsTests.map((t) => ({
|
|
405
|
+
name: t.testName,
|
|
406
|
+
passed: t.testPassed,
|
|
407
|
+
duration: t.testDuration,
|
|
408
|
+
error: t.testError,
|
|
409
|
+
screenshot: t.testScreenshot
|
|
410
|
+
})),
|
|
411
|
+
coverage: data.resultsCoverage,
|
|
412
|
+
metrics: Object.fromEntries(data.resultsMetrics || [])
|
|
685
413
|
};
|
|
686
414
|
};
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
const apiUrl = config.apiUrl || "https://api.forboc.ai";
|
|
691
|
-
try {
|
|
692
|
-
const response = await fetch(`${apiUrl}/ghost/run`, {
|
|
693
|
-
method: "POST",
|
|
694
|
-
headers: { "Content-Type": "application/json" },
|
|
695
|
-
body: JSON.stringify({
|
|
696
|
-
testSuite: config.testSuite,
|
|
697
|
-
duration: config.duration
|
|
698
|
-
})
|
|
699
|
-
});
|
|
700
|
-
if (!response.ok) {
|
|
701
|
-
throw new Error(`Failed to start Ghost session: ${response.statusText}`);
|
|
702
|
-
}
|
|
703
|
-
const data = await response.json();
|
|
704
|
-
return {
|
|
705
|
-
sessionId: data.sessionId,
|
|
706
|
-
status: data.runStatus
|
|
707
|
-
};
|
|
708
|
-
} catch (e) {
|
|
709
|
-
const mockId = `ghost_${Date.now()}_${Math.random().toString(36).substring(7)}`;
|
|
710
|
-
return {
|
|
711
|
-
sessionId: mockId,
|
|
712
|
-
status: "running"
|
|
713
|
-
};
|
|
714
|
-
}
|
|
715
|
-
};
|
|
716
|
-
var getGhostStatus = async (sessionId, apiUrl) => {
|
|
717
|
-
const url = apiUrl || "https://api.forboc.ai";
|
|
718
|
-
try {
|
|
719
|
-
const response = await fetch(`${url}/ghost/${sessionId}/status`, {
|
|
720
|
-
method: "GET",
|
|
721
|
-
headers: { "Content-Type": "application/json" }
|
|
722
|
-
});
|
|
723
|
-
if (!response.ok) {
|
|
724
|
-
throw new Error(`Failed to get Ghost status: ${response.statusText}`);
|
|
725
|
-
}
|
|
726
|
-
const data = await response.json();
|
|
727
|
-
return {
|
|
728
|
-
sessionId: data.ghostSessionId,
|
|
729
|
-
status: data.ghostStatus,
|
|
730
|
-
progress: data.ghostProgress,
|
|
731
|
-
startedAt: data.ghostStartedAt,
|
|
732
|
-
duration: data.ghostDuration,
|
|
733
|
-
errors: data.ghostErrors
|
|
734
|
-
};
|
|
735
|
-
} catch (e) {
|
|
736
|
-
return {
|
|
737
|
-
sessionId,
|
|
738
|
-
status: "running",
|
|
739
|
-
progress: Math.floor(Math.random() * 100),
|
|
740
|
-
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
741
|
-
duration: 60,
|
|
742
|
-
errors: 0
|
|
743
|
-
};
|
|
415
|
+
var pollForCompletion = async (sessionId, pollIntervalMs, timeoutMs, startTime, apiUrl, onProgress) => {
|
|
416
|
+
if (Date.now() - startTime > timeoutMs) {
|
|
417
|
+
throw new Error(`Ghost session timed out after ${timeoutMs}ms`);
|
|
744
418
|
}
|
|
745
|
-
};
|
|
746
|
-
var getGhostResults = async (sessionId, apiUrl) => {
|
|
747
|
-
const url = apiUrl || "https://api.forboc.ai";
|
|
748
419
|
try {
|
|
749
|
-
const
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
});
|
|
753
|
-
if (!response.ok) {
|
|
754
|
-
throw new Error(`Failed to get Ghost results: ${response.statusText}`);
|
|
755
|
-
}
|
|
756
|
-
const data = await response.json();
|
|
757
|
-
return {
|
|
758
|
-
sessionId: data.resultsSessionId,
|
|
759
|
-
totalTests: data.resultsTotalTests,
|
|
760
|
-
passed: data.resultsPassed,
|
|
761
|
-
failed: data.resultsFailed,
|
|
762
|
-
skipped: data.resultsSkipped,
|
|
763
|
-
duration: data.resultsDuration,
|
|
764
|
-
tests: data.resultsTests.map((t) => ({
|
|
765
|
-
name: t.testName,
|
|
766
|
-
passed: t.testPassed,
|
|
767
|
-
duration: t.testDuration,
|
|
768
|
-
error: t.testError,
|
|
769
|
-
screenshot: t.testScreenshot
|
|
770
|
-
})),
|
|
771
|
-
coverage: data.resultsCoverage,
|
|
772
|
-
metrics: Object.fromEntries(data.resultsMetrics)
|
|
773
|
-
};
|
|
420
|
+
const status = await getGhostStatus(sessionId, apiUrl);
|
|
421
|
+
if (onProgress) onProgress(status);
|
|
422
|
+
if (status.status === "completed") return getGhostResults(sessionId, apiUrl);
|
|
423
|
+
if (status.status === "failed") throw new Error(`Ghost session failed with ${status.errors} errors`);
|
|
774
424
|
} catch (e) {
|
|
775
|
-
return {
|
|
776
|
-
sessionId,
|
|
777
|
-
totalTests: 5,
|
|
778
|
-
passed: 4,
|
|
779
|
-
failed: 1,
|
|
780
|
-
skipped: 0,
|
|
781
|
-
duration: 1245,
|
|
782
|
-
tests: [
|
|
783
|
-
{ name: "test.navigation", passed: true, duration: 150 },
|
|
784
|
-
{ name: "test.combat", passed: true, duration: 230 },
|
|
785
|
-
{ name: "test.dialogue", passed: false, duration: 450, error: "Timeout" }
|
|
786
|
-
],
|
|
787
|
-
coverage: 0.75,
|
|
788
|
-
metrics: {
|
|
789
|
-
avgFrameRate: 58.5,
|
|
790
|
-
memoryUsageMB: 512.3,
|
|
791
|
-
aiDecisionsPerSec: 15.2
|
|
792
|
-
}
|
|
793
|
-
};
|
|
794
|
-
}
|
|
795
|
-
};
|
|
796
|
-
var waitForGhostCompletion = async (sessionId, pollIntervalMs = 5e3, timeoutMs = 3e5, apiUrl, onProgress) => {
|
|
797
|
-
const startTime = Date.now();
|
|
798
|
-
while (Date.now() - startTime < timeoutMs) {
|
|
799
|
-
try {
|
|
800
|
-
const status = await getGhostStatus(sessionId, apiUrl);
|
|
801
|
-
if (onProgress) {
|
|
802
|
-
onProgress(status);
|
|
803
|
-
}
|
|
804
|
-
if (status.status === "completed") {
|
|
805
|
-
return getGhostResults(sessionId, apiUrl);
|
|
806
|
-
}
|
|
807
|
-
if (status.status === "failed") {
|
|
808
|
-
throw new Error(`Ghost session failed with ${status.errors} errors`);
|
|
809
|
-
}
|
|
810
|
-
} catch (e) {
|
|
811
|
-
}
|
|
812
|
-
await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
|
|
813
425
|
}
|
|
814
|
-
|
|
426
|
+
await delay(pollIntervalMs);
|
|
427
|
+
return pollForCompletion(sessionId, pollIntervalMs, timeoutMs, startTime, apiUrl, onProgress);
|
|
815
428
|
};
|
|
429
|
+
var waitForGhostCompletion = (sessionId, pollIntervalMs = 5e3, timeoutMs = 3e5, apiUrl, onProgress) => pollForCompletion(sessionId, pollIntervalMs, timeoutMs, Date.now(), apiUrl, onProgress);
|
|
816
430
|
var stopGhostSession = async (sessionId, apiUrl) => {
|
|
817
|
-
const url = apiUrl ||
|
|
431
|
+
const url = apiUrl || DEFAULT_API_URL;
|
|
818
432
|
try {
|
|
819
|
-
const response = await fetch(`${url}/ghost/${sessionId}/stop`, {
|
|
820
|
-
|
|
821
|
-
headers: { "Content-Type": "application/json" }
|
|
822
|
-
});
|
|
823
|
-
if (!response.ok) {
|
|
824
|
-
throw new Error(`Failed to stop Ghost session: ${response.statusText}`);
|
|
825
|
-
}
|
|
826
|
-
const data = await response.json();
|
|
827
|
-
return {
|
|
828
|
-
stopped: true,
|
|
829
|
-
status: data.status || "stopped"
|
|
830
|
-
};
|
|
433
|
+
const response = await fetch(`${url}/ghost/${sessionId}/stop`, { method: "POST" });
|
|
434
|
+
return { stopped: response.ok };
|
|
831
435
|
} catch (e) {
|
|
832
|
-
return {
|
|
833
|
-
stopped: true,
|
|
834
|
-
status: "stopped"
|
|
835
|
-
};
|
|
436
|
+
return { stopped: true };
|
|
836
437
|
}
|
|
837
438
|
};
|
|
838
439
|
var getGhostHistory = async (limit = 10, apiUrl) => {
|
|
839
|
-
const url = apiUrl ||
|
|
440
|
+
const url = apiUrl || DEFAULT_API_URL;
|
|
840
441
|
try {
|
|
841
|
-
const response = await fetch(`${url}/ghost/history?limit=${limit}
|
|
842
|
-
|
|
843
|
-
headers: { "Content-Type": "application/json" }
|
|
844
|
-
});
|
|
845
|
-
if (!response.ok) {
|
|
846
|
-
throw new Error(`Failed to get Ghost history: ${response.statusText}`);
|
|
847
|
-
}
|
|
442
|
+
const response = await fetch(`${url}/ghost/history?limit=${limit}`);
|
|
443
|
+
if (!response.ok) return [];
|
|
848
444
|
const data = await response.json();
|
|
849
445
|
return data.sessions.map((s) => ({
|
|
850
446
|
sessionId: s.sessionId,
|
|
@@ -859,54 +455,33 @@ var getGhostHistory = async (limit = 10, apiUrl) => {
|
|
|
859
455
|
}
|
|
860
456
|
};
|
|
861
457
|
var createGhost = (config) => {
|
|
862
|
-
let
|
|
863
|
-
const apiUrl = config.apiUrl ||
|
|
458
|
+
let _sessionId = null;
|
|
459
|
+
const apiUrl = config.apiUrl || DEFAULT_API_URL;
|
|
864
460
|
const run = async () => {
|
|
865
461
|
const result = await startGhostSession(config);
|
|
866
|
-
|
|
867
|
-
return
|
|
868
|
-
};
|
|
869
|
-
const status = async () => {
|
|
870
|
-
if (!sessionId) {
|
|
871
|
-
throw new Error("Ghost session not started");
|
|
872
|
-
}
|
|
873
|
-
return getGhostStatus(sessionId, apiUrl);
|
|
462
|
+
_sessionId = result.sessionId;
|
|
463
|
+
return _sessionId;
|
|
874
464
|
};
|
|
875
|
-
const
|
|
876
|
-
if (!
|
|
877
|
-
|
|
878
|
-
}
|
|
879
|
-
return getGhostResults(sessionId, apiUrl);
|
|
465
|
+
const ensureSessionId = () => {
|
|
466
|
+
if (!_sessionId) throw new Error("Ghost session not started");
|
|
467
|
+
return _sessionId;
|
|
880
468
|
};
|
|
469
|
+
const status = async () => getGhostStatus(ensureSessionId(), apiUrl);
|
|
470
|
+
const results = async () => getGhostResults(ensureSessionId(), apiUrl);
|
|
881
471
|
const stop = async () => {
|
|
882
|
-
if (
|
|
883
|
-
|
|
884
|
-
}
|
|
885
|
-
sessionId = null;
|
|
886
|
-
};
|
|
887
|
-
const waitForCompletion = async (pollIntervalMs, timeoutMs, onProgress) => {
|
|
888
|
-
if (!sessionId) {
|
|
889
|
-
throw new Error("Ghost session not started");
|
|
890
|
-
}
|
|
891
|
-
return waitForGhostCompletion(
|
|
892
|
-
sessionId,
|
|
893
|
-
pollIntervalMs,
|
|
894
|
-
timeoutMs,
|
|
895
|
-
apiUrl,
|
|
896
|
-
onProgress
|
|
897
|
-
);
|
|
898
|
-
};
|
|
899
|
-
return {
|
|
900
|
-
run,
|
|
901
|
-
status,
|
|
902
|
-
results,
|
|
903
|
-
stop,
|
|
904
|
-
waitForCompletion
|
|
472
|
+
if (_sessionId) await stopGhostSession(_sessionId, apiUrl);
|
|
473
|
+
_sessionId = null;
|
|
905
474
|
};
|
|
475
|
+
const waitForCompletion = (pollIntervalMs, timeoutMs, onProgress) => waitForGhostCompletion(ensureSessionId(), pollIntervalMs, timeoutMs, apiUrl, onProgress);
|
|
476
|
+
return { run, status, results, stop, waitForCompletion };
|
|
906
477
|
};
|
|
907
478
|
|
|
908
479
|
// src/cortex-remote.ts
|
|
909
|
-
var createRemoteCortex = (apiUrl, cortexId = "local") => {
|
|
480
|
+
var createRemoteCortex = (apiUrl, cortexId = "local", apiKey) => {
|
|
481
|
+
const authHeaders = {
|
|
482
|
+
"Content-Type": "application/json",
|
|
483
|
+
...apiKey ? { "Authorization": `Bearer ${apiKey}` } : {}
|
|
484
|
+
};
|
|
910
485
|
const init = async () => ({
|
|
911
486
|
id: `remote_${Date.now()}`,
|
|
912
487
|
model: "api-integrated",
|
|
@@ -916,7 +491,7 @@ var createRemoteCortex = (apiUrl, cortexId = "local") => {
|
|
|
916
491
|
const complete = async (prompt, options) => {
|
|
917
492
|
const response = await fetch(`${apiUrl}/cortex/${cortexId}/complete`, {
|
|
918
493
|
method: "POST",
|
|
919
|
-
headers:
|
|
494
|
+
headers: authHeaders,
|
|
920
495
|
body: JSON.stringify({ prompt, ...options })
|
|
921
496
|
});
|
|
922
497
|
if (!response.ok) throw new Error(`Remote Cortex failed: ${response.statusText}`);
|
|
@@ -930,214 +505,32 @@ var createRemoteCortex = (apiUrl, cortexId = "local") => {
|
|
|
930
505
|
return { init, complete, completeStream };
|
|
931
506
|
};
|
|
932
507
|
|
|
933
|
-
// src/
|
|
934
|
-
var
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
});
|
|
949
|
-
|
|
950
|
-
// src/presets/rpg.ts
|
|
951
|
-
var RPG_MOODS = {
|
|
952
|
-
hostile: "hostile",
|
|
953
|
-
suspicious: "suspicious",
|
|
954
|
-
neutral: "neutral",
|
|
955
|
-
friendly: "friendly",
|
|
956
|
-
loyal: "loyal"
|
|
957
|
-
};
|
|
958
|
-
var RPG_MEMORY_TYPES = {
|
|
959
|
-
observation: "observation",
|
|
960
|
-
experience: "experience",
|
|
961
|
-
knowledge: "knowledge",
|
|
962
|
-
emotion: "emotion"
|
|
963
|
-
};
|
|
964
|
-
var createRPGState = (partial) => {
|
|
965
|
-
return {
|
|
966
|
-
inventory: partial?.inventory ?? [],
|
|
967
|
-
hp: partial?.hp ?? 100,
|
|
968
|
-
mana: partial?.mana ?? 100,
|
|
969
|
-
skills: partial?.skills ?? {},
|
|
970
|
-
relationships: partial?.relationships ?? {},
|
|
971
|
-
mood: partial?.mood ?? "neutral",
|
|
972
|
-
...partial
|
|
973
|
-
};
|
|
974
|
-
};
|
|
975
|
-
var movementRule = {
|
|
976
|
-
id: "core.movement",
|
|
977
|
-
name: "Movement Validation",
|
|
978
|
-
description: "Ensures MOVE actions have valid x,y coordinates",
|
|
979
|
-
actionTypes: ["MOVE", "move"],
|
|
980
|
-
validate: (action, context) => {
|
|
981
|
-
const payload = action.payload || {};
|
|
982
|
-
const target = payload.target;
|
|
983
|
-
if (!target || typeof target.x !== "number" || typeof target.y !== "number") {
|
|
984
|
-
return {
|
|
985
|
-
valid: false,
|
|
986
|
-
reason: "MOVE action must have target with numeric x,y coordinates",
|
|
987
|
-
correctedAction: {
|
|
988
|
-
...action,
|
|
989
|
-
type: "IDLE",
|
|
990
|
-
reason: "Invalid MOVE target - defaulting to IDLE"
|
|
991
|
-
}
|
|
992
|
-
};
|
|
993
|
-
}
|
|
994
|
-
const world = context.worldState || {};
|
|
995
|
-
const maxX = world.maxX || Infinity;
|
|
996
|
-
const maxY = world.maxY || Infinity;
|
|
997
|
-
if (target.x < 0 || target.x > maxX || target.y < 0 || target.y > maxY) {
|
|
998
|
-
return {
|
|
999
|
-
valid: false,
|
|
1000
|
-
reason: `MOVE target (${target.x}, ${target.y}) is out of bounds`,
|
|
1001
|
-
correctedAction: {
|
|
1002
|
-
...action,
|
|
1003
|
-
payload: {
|
|
1004
|
-
...payload,
|
|
1005
|
-
target: {
|
|
1006
|
-
x: Math.max(0, Math.min(maxX, target.x)),
|
|
1007
|
-
y: Math.max(0, Math.min(maxY, target.y))
|
|
1008
|
-
}
|
|
1009
|
-
}
|
|
1010
|
-
}
|
|
1011
|
-
};
|
|
1012
|
-
}
|
|
1013
|
-
return { valid: true };
|
|
1014
|
-
}
|
|
1015
|
-
};
|
|
1016
|
-
var attackRule = {
|
|
1017
|
-
id: "core.attack",
|
|
1018
|
-
name: "Attack Validation",
|
|
1019
|
-
description: "Ensures ATTACK actions have valid targetId",
|
|
1020
|
-
actionTypes: ["ATTACK", "attack"],
|
|
1021
|
-
validate: (action, context) => {
|
|
1022
|
-
if (!action.target && !action.payload?.targetId) {
|
|
1023
|
-
return {
|
|
1024
|
-
valid: false,
|
|
1025
|
-
reason: "ATTACK action must have a target or targetId",
|
|
1026
|
-
correctedAction: {
|
|
1027
|
-
...action,
|
|
1028
|
-
type: "IDLE",
|
|
1029
|
-
reason: "Invalid ATTACK - no target specified"
|
|
1030
|
-
}
|
|
1031
|
-
};
|
|
1032
|
-
}
|
|
1033
|
-
const world = context.worldState || {};
|
|
1034
|
-
const entities = world.entities || [];
|
|
1035
|
-
const targetId = action.target || action.payload?.targetId;
|
|
1036
|
-
if (entities.length > 0 && !entities.includes(targetId)) {
|
|
1037
|
-
return {
|
|
1038
|
-
valid: false,
|
|
1039
|
-
reason: `ATTACK target '${targetId}' does not exist in world`,
|
|
1040
|
-
correctedAction: {
|
|
1041
|
-
...action,
|
|
1042
|
-
type: "IDLE",
|
|
1043
|
-
reason: "Target not found"
|
|
1044
|
-
}
|
|
1045
|
-
};
|
|
1046
|
-
}
|
|
1047
|
-
return { valid: true };
|
|
1048
|
-
}
|
|
1049
|
-
};
|
|
1050
|
-
var interactRule = {
|
|
1051
|
-
id: "core.interact",
|
|
1052
|
-
name: "Interact Validation",
|
|
1053
|
-
description: "Ensures INTERACT actions have valid objectId",
|
|
1054
|
-
actionTypes: ["INTERACT", "interact"],
|
|
1055
|
-
validate: (action, context) => {
|
|
1056
|
-
if (!action.target && !action.payload?.objectId) {
|
|
1057
|
-
return {
|
|
1058
|
-
valid: false,
|
|
1059
|
-
reason: "INTERACT action must have objectId",
|
|
1060
|
-
correctedAction: {
|
|
1061
|
-
...action,
|
|
1062
|
-
type: "IDLE",
|
|
1063
|
-
reason: "Invalid INTERACT - no object specified"
|
|
1064
|
-
}
|
|
1065
|
-
};
|
|
1066
|
-
}
|
|
1067
|
-
return { valid: true };
|
|
1068
|
-
}
|
|
508
|
+
// src/stream.ts
|
|
509
|
+
var consumeStream = async (stream, onChunk, acc = "", delayMs = 0) => {
|
|
510
|
+
const { value, done } = await stream.next();
|
|
511
|
+
if (done) return acc;
|
|
512
|
+
const chunk = value ?? "";
|
|
513
|
+
onChunk(chunk);
|
|
514
|
+
if (delayMs > 0) await delay(delayMs);
|
|
515
|
+
return consumeStream(stream, onChunk, acc + chunk, delayMs);
|
|
516
|
+
};
|
|
517
|
+
var streamToCallback = async (stream, onChunk) => {
|
|
518
|
+
await consumeStream(stream, onChunk);
|
|
519
|
+
};
|
|
520
|
+
var streamToString = async (stream) => {
|
|
521
|
+
return consumeStream(stream, () => {
|
|
522
|
+
});
|
|
1069
523
|
};
|
|
1070
|
-
var
|
|
1071
|
-
|
|
1072
|
-
name: "Speak Validation",
|
|
1073
|
-
description: "Ensures SPEAK actions have non-empty text",
|
|
1074
|
-
actionTypes: ["SPEAK", "speak"],
|
|
1075
|
-
validate: (action, context) => {
|
|
1076
|
-
const text = action.payload?.text;
|
|
1077
|
-
if (!text || text.trim().length === 0) {
|
|
1078
|
-
return {
|
|
1079
|
-
valid: false,
|
|
1080
|
-
reason: "SPEAK action must have non-empty text",
|
|
1081
|
-
correctedAction: {
|
|
1082
|
-
...action,
|
|
1083
|
-
type: "IDLE",
|
|
1084
|
-
reason: "Empty speech - defaulting to IDLE"
|
|
1085
|
-
}
|
|
1086
|
-
};
|
|
1087
|
-
}
|
|
1088
|
-
const maxLength = context.constraints?.maxSpeechLength || 1e3;
|
|
1089
|
-
if (text.length > maxLength) {
|
|
1090
|
-
return {
|
|
1091
|
-
valid: true,
|
|
1092
|
-
reason: `Speech truncated to ${maxLength} characters`,
|
|
1093
|
-
correctedAction: {
|
|
1094
|
-
...action,
|
|
1095
|
-
payload: {
|
|
1096
|
-
...action.payload,
|
|
1097
|
-
text: text.substring(0, maxLength)
|
|
1098
|
-
}
|
|
1099
|
-
}
|
|
1100
|
-
};
|
|
1101
|
-
}
|
|
1102
|
-
return { valid: true };
|
|
1103
|
-
}
|
|
524
|
+
var streamFromCortex = async (cortex, prompt, onChunk, options) => {
|
|
525
|
+
return consumeStream(cortex.completeStream(prompt, options), onChunk);
|
|
1104
526
|
};
|
|
1105
|
-
var
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
description: "Ensures agent has required resources for action",
|
|
1109
|
-
actionTypes: ["ATTACK", "CAST", "USE_ITEM"],
|
|
1110
|
-
validate: (action, context) => {
|
|
1111
|
-
const agent = context.agentState || {};
|
|
1112
|
-
const hp = agent.hp ?? 100;
|
|
1113
|
-
const mana = agent.mana ?? 100;
|
|
1114
|
-
if (hp <= 0) {
|
|
1115
|
-
return {
|
|
1116
|
-
valid: false,
|
|
1117
|
-
reason: "Agent is dead and cannot perform actions",
|
|
1118
|
-
correctedAction: { ...action, type: "IDLE", reason: "Agent dead" }
|
|
1119
|
-
};
|
|
1120
|
-
}
|
|
1121
|
-
if (action.type === "CAST" || action.type === "cast") {
|
|
1122
|
-
const manaCost = action.payload?.manaCost || 10;
|
|
1123
|
-
if (mana < manaCost) {
|
|
1124
|
-
return {
|
|
1125
|
-
valid: false,
|
|
1126
|
-
reason: `Insufficient mana: need ${manaCost}, have ${mana}`,
|
|
1127
|
-
correctedAction: { ...action, type: "IDLE", reason: "Not enough mana" }
|
|
1128
|
-
};
|
|
1129
|
-
}
|
|
1130
|
-
}
|
|
1131
|
-
return { valid: true };
|
|
1132
|
-
}
|
|
527
|
+
var streamFromCortexWithDelay = async (cortex, prompt, onChunk, options) => {
|
|
528
|
+
const { delayMs = 30, ...completionOptions } = options ?? {};
|
|
529
|
+
return consumeStream(cortex.completeStream(prompt, completionOptions), onChunk, "", delayMs);
|
|
1133
530
|
};
|
|
1134
|
-
var rpgRules = [movementRule, attackRule, interactRule, speakRule, resourceRule];
|
|
1135
|
-
var spatialRules = [movementRule];
|
|
1136
|
-
var socialRules = [speakRule, interactRule];
|
|
1137
|
-
var puzzleRules = [movementRule, interactRule];
|
|
1138
531
|
|
|
1139
532
|
// src/index.ts
|
|
1140
|
-
var SDK_VERSION = "0.5.
|
|
533
|
+
var SDK_VERSION = "0.5.7";
|
|
1141
534
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1142
535
|
0 && (module.exports = {
|
|
1143
536
|
SDK_VERSION,
|
|
@@ -1148,6 +541,7 @@ var SDK_VERSION = "0.5.6";
|
|
|
1148
541
|
createRemoteCortex,
|
|
1149
542
|
createSoul,
|
|
1150
543
|
createSoulInstance,
|
|
544
|
+
delay,
|
|
1151
545
|
deserializeSoul,
|
|
1152
546
|
exportSoul,
|
|
1153
547
|
exportToSoul,
|
|
@@ -1157,12 +551,18 @@ var SDK_VERSION = "0.5.6";
|
|
|
1157
551
|
getGhostStatus,
|
|
1158
552
|
getSoulList,
|
|
1159
553
|
importSoulFromArweave,
|
|
1160
|
-
|
|
554
|
+
loadPreset,
|
|
555
|
+
memoise,
|
|
556
|
+
memoiseAsync,
|
|
557
|
+
pipe,
|
|
1161
558
|
serializeSoul,
|
|
1162
559
|
startGhostSession,
|
|
1163
560
|
stopGhostSession,
|
|
561
|
+
streamFromCortex,
|
|
562
|
+
streamFromCortexWithDelay,
|
|
563
|
+
streamToCallback,
|
|
564
|
+
streamToString,
|
|
1164
565
|
updateAgentState,
|
|
1165
|
-
uploadToArweave,
|
|
1166
566
|
validateAction,
|
|
1167
567
|
validateSoul,
|
|
1168
568
|
waitForGhostCompletion
|