@forbocai/core 0.5.7 → 0.5.9
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 +90 -285
- package/dist/index.d.ts +90 -285
- package/dist/index.js +314 -987
- package/dist/index.mjs +239 -761
- 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,7 +131,10 @@ __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,
|
|
@@ -289,7 +143,6 @@ __export(index_exports, {
|
|
|
289
143
|
streamToCallback: () => streamToCallback,
|
|
290
144
|
streamToString: () => streamToString,
|
|
291
145
|
updateAgentState: () => updateAgentState,
|
|
292
|
-
uploadToArweave: () => uploadToArweave,
|
|
293
146
|
validateAction: () => validateAction,
|
|
294
147
|
validateSoul: () => validateSoul,
|
|
295
148
|
waitForGhostCompletion: () => waitForGhostCompletion
|
|
@@ -297,168 +150,114 @@ __export(index_exports, {
|
|
|
297
150
|
module.exports = __toCommonJS(index_exports);
|
|
298
151
|
|
|
299
152
|
// src/agent.ts
|
|
300
|
-
var createInitialState = (partial) => {
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
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);
|
|
318
171
|
};
|
|
319
172
|
var createAgent = (config) => {
|
|
320
|
-
let
|
|
173
|
+
let _state = createInitialState(config.initialState);
|
|
321
174
|
const cortex = config.cortex;
|
|
322
175
|
const apiUrl = config.apiUrl || "https://api.forboc.ai";
|
|
323
176
|
const agentId = config.id || "agent-" + Math.random().toString(36).substring(7);
|
|
324
177
|
const authHeaders = config.apiKey ? { "Content-Type": "application/json", "Authorization": `Bearer ${config.apiKey}` } : { "Content-Type": "application/json" };
|
|
325
|
-
const
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
const setAgentState = (newState) => {
|
|
329
|
-
state = newState;
|
|
178
|
+
const getState = () => ({ ..._state });
|
|
179
|
+
const setState = (newState) => {
|
|
180
|
+
_state = newState;
|
|
330
181
|
};
|
|
331
182
|
const process = async (input, context = {}) => {
|
|
332
|
-
const currentState =
|
|
333
|
-
const directiveBody = {
|
|
334
|
-
observation: input,
|
|
335
|
-
agentState: currentState,
|
|
336
|
-
context
|
|
337
|
-
};
|
|
183
|
+
const currentState = getState();
|
|
338
184
|
const dirRes = await fetch(`${apiUrl}/agents/${agentId}/directive`, {
|
|
339
185
|
method: "POST",
|
|
340
186
|
headers: authHeaders,
|
|
341
|
-
body: JSON.stringify(
|
|
187
|
+
body: JSON.stringify({ observation: input, agentState: currentState, context })
|
|
342
188
|
});
|
|
343
|
-
if (!dirRes.ok) {
|
|
344
|
-
throw new Error(`API Directive Error: ${dirRes.status}`);
|
|
345
|
-
}
|
|
189
|
+
if (!dirRes.ok) throw new Error(`API Directive Error: ${dirRes.status}`);
|
|
346
190
|
const directiveData = await dirRes.json();
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
directiveData.memoryRecall.limit,
|
|
353
|
-
directiveData.memoryRecall.threshold
|
|
354
|
-
);
|
|
355
|
-
recalledMemories = rawMemories.map((m) => ({
|
|
356
|
-
text: m.text,
|
|
357
|
-
type: m.type,
|
|
358
|
-
importance: m.importance,
|
|
359
|
-
similarity: void 0
|
|
360
|
-
}));
|
|
361
|
-
} catch (e) {
|
|
362
|
-
console.warn("Memory recall failed, continuing with empty memories:", e);
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
const contextBody = {
|
|
366
|
-
memories: recalledMemories,
|
|
367
|
-
observation: input,
|
|
368
|
-
agentState: currentState
|
|
369
|
-
};
|
|
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(() => []) : [];
|
|
370
196
|
const ctxRes = await fetch(`${apiUrl}/agents/${agentId}/context`, {
|
|
371
197
|
method: "POST",
|
|
372
198
|
headers: authHeaders,
|
|
373
|
-
body: JSON.stringify(
|
|
199
|
+
body: JSON.stringify({ memories: recalledMemories, observation: input, agentState: currentState })
|
|
374
200
|
});
|
|
375
|
-
if (!ctxRes.ok) {
|
|
376
|
-
throw new Error(`API Context Error: ${ctxRes.status}`);
|
|
377
|
-
}
|
|
201
|
+
if (!ctxRes.ok) throw new Error(`API Context Error: ${ctxRes.status}`);
|
|
378
202
|
const contextData = await ctxRes.json();
|
|
379
203
|
const generatedText = await cortex.complete(contextData.prompt, {
|
|
380
204
|
maxTokens: contextData.constraints.maxTokens,
|
|
381
205
|
temperature: contextData.constraints.temperature,
|
|
382
206
|
stop: contextData.constraints.stop
|
|
383
207
|
});
|
|
384
|
-
const verdictBody = {
|
|
385
|
-
generatedOutput: generatedText,
|
|
386
|
-
observation: input,
|
|
387
|
-
agentState: currentState
|
|
388
|
-
};
|
|
389
208
|
const verRes = await fetch(`${apiUrl}/agents/${agentId}/verdict`, {
|
|
390
209
|
method: "POST",
|
|
391
210
|
headers: authHeaders,
|
|
392
|
-
body: JSON.stringify(
|
|
211
|
+
body: JSON.stringify({ generatedOutput: generatedText, observation: input, agentState: currentState })
|
|
393
212
|
});
|
|
394
|
-
if (!verRes.ok) {
|
|
395
|
-
throw new Error(`API Verdict Error: ${verRes.status}`);
|
|
396
|
-
}
|
|
213
|
+
if (!verRes.ok) throw new Error(`API Verdict Error: ${verRes.status}`);
|
|
397
214
|
const verdictData = await verRes.json();
|
|
398
215
|
if (!verdictData.valid) {
|
|
399
|
-
return {
|
|
400
|
-
dialogue: "... [Action Blocked by Protocol]",
|
|
401
|
-
action: { type: "BLOCKED", reason: "API Validation Failed" }
|
|
402
|
-
};
|
|
216
|
+
return { dialogue: "... [Blocked]", action: { type: "BLOCKED", reason: "Validation Failed" } };
|
|
403
217
|
}
|
|
404
|
-
if (config.memory &&
|
|
405
|
-
|
|
406
|
-
config.memory.store(instruction.text, instruction.type, instruction.importance).catch((e) => console.warn("Memory store failed:", e));
|
|
407
|
-
}
|
|
218
|
+
if (config.memory && verdictData.memoryStore) {
|
|
219
|
+
storeMemoriesRecursive(config.memory, verdictData.memoryStore);
|
|
408
220
|
}
|
|
409
|
-
if (verdictData.stateDelta
|
|
410
|
-
|
|
221
|
+
if (verdictData.stateDelta) {
|
|
222
|
+
setState(updateAgentState(_state, verdictData.stateDelta));
|
|
411
223
|
}
|
|
412
224
|
return {
|
|
413
225
|
dialogue: generatedText,
|
|
414
|
-
action: verdictData.action ? {
|
|
415
|
-
...verdictData.action,
|
|
416
|
-
signature: verdictData.signature
|
|
417
|
-
} : void 0,
|
|
226
|
+
action: verdictData.action ? { ...verdictData.action, signature: verdictData.signature } : void 0,
|
|
418
227
|
thought: generatedText
|
|
419
228
|
};
|
|
420
229
|
};
|
|
421
230
|
const speak = async (message, context = {}) => {
|
|
422
|
-
const currentState = getAgentState();
|
|
423
|
-
const speakBody = {
|
|
424
|
-
speakMessage: message,
|
|
425
|
-
speakContext: Object.keys(context).length > 0 ? context : void 0,
|
|
426
|
-
speakAgentState: currentState
|
|
427
|
-
};
|
|
428
231
|
const res = await fetch(`${apiUrl}/agents/${agentId}/speak`, {
|
|
429
232
|
method: "POST",
|
|
430
233
|
headers: authHeaders,
|
|
431
|
-
body: JSON.stringify(
|
|
234
|
+
body: JSON.stringify({ speakMessage: message, speakContext: context, speakAgentState: getState() })
|
|
432
235
|
});
|
|
433
|
-
if (!res.ok) {
|
|
434
|
-
throw new Error(`API Speak Error: ${res.status}`);
|
|
435
|
-
}
|
|
236
|
+
if (!res.ok) throw new Error(`API Speak Error: ${res.status}`);
|
|
436
237
|
const data = await res.json();
|
|
437
|
-
if (data.speakHistory) {
|
|
438
|
-
state = updateAgentState(state, { conversationHistory: data.speakHistory });
|
|
439
|
-
}
|
|
238
|
+
if (data.speakHistory) setState(updateAgentState(_state, { conversationHistory: data.speakHistory }));
|
|
440
239
|
return data.speakReply;
|
|
441
240
|
};
|
|
442
|
-
const
|
|
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
|
+
};
|
|
443
251
|
const exportSoul2 = async () => {
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
try {
|
|
447
|
-
exportedMemories = await config.memory.export();
|
|
448
|
-
} catch (e) {
|
|
449
|
-
console.warn("Memory export failed, exporting with empty memories:", e);
|
|
450
|
-
}
|
|
451
|
-
}
|
|
452
|
-
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);
|
|
453
254
|
};
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
getState: getAgentState,
|
|
459
|
-
setState: setAgentState,
|
|
460
|
-
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 });
|
|
461
259
|
};
|
|
260
|
+
return { process, speak, dialogue, reply: speak, getState, setState, export: exportSoul2, exportSoul: exportSoulToArweave };
|
|
462
261
|
};
|
|
463
262
|
var fromSoul = async (soul, cortex, memory) => {
|
|
464
263
|
const agent = createAgent({
|
|
@@ -468,412 +267,180 @@ var fromSoul = async (soul, cortex, memory) => {
|
|
|
468
267
|
persona: soul.persona,
|
|
469
268
|
initialState: soul.state
|
|
470
269
|
});
|
|
471
|
-
if (memory && soul.memories && soul.memories.length > 0
|
|
472
|
-
|
|
473
|
-
await memory.import(soul.memories);
|
|
474
|
-
} catch (e) {
|
|
475
|
-
console.warn("Memory hydration failed, continuing without memories:", e);
|
|
476
|
-
}
|
|
270
|
+
if (memory && soul.memories && soul.memories.length > 0) {
|
|
271
|
+
await memory.import(soul.memories).catch((e) => console.warn("Memory hydration failed:", e));
|
|
477
272
|
}
|
|
478
273
|
return agent;
|
|
479
274
|
};
|
|
480
275
|
|
|
481
276
|
// src/bridge.ts
|
|
482
277
|
var createBridge = (config = {}) => {
|
|
483
|
-
const
|
|
484
|
-
|
|
485
|
-
...config
|
|
486
|
-
};
|
|
487
|
-
const rules = /* @__PURE__ */ new Map();
|
|
488
|
-
if (config.customRules) {
|
|
489
|
-
config.customRules.forEach((rule) => rules.set(rule.id, rule));
|
|
490
|
-
}
|
|
491
|
-
const validateRemote = async (action) => {
|
|
492
|
-
const response = await fetch(`${effectiveConfig.apiUrl}/bridge/validate`, {
|
|
493
|
-
method: "POST",
|
|
494
|
-
headers: { "Content-Type": "application/json" },
|
|
495
|
-
body: JSON.stringify({
|
|
496
|
-
actionType: action.type,
|
|
497
|
-
payload: JSON.stringify(action.payload || {})
|
|
498
|
-
})
|
|
499
|
-
});
|
|
500
|
-
if (!response.ok) {
|
|
501
|
-
throw new Error(`API validation failed: ${response.statusText}`);
|
|
502
|
-
}
|
|
503
|
-
const data = await response.json();
|
|
504
|
-
return {
|
|
505
|
-
valid: data.valid,
|
|
506
|
-
reason: data.reason
|
|
507
|
-
};
|
|
508
|
-
};
|
|
278
|
+
const apiUrl = config.apiUrl || "https://api.forboc.ai";
|
|
279
|
+
const agentId = config.agentId;
|
|
509
280
|
const validate = async (action, context = {}) => {
|
|
510
|
-
const
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
if (!
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
reason: `Unknown action type '${action.type}' in strict mode`,
|
|
521
|
-
correctedAction: { ...action, type: "IDLE", reason: "Unknown action type" }
|
|
522
|
-
};
|
|
523
|
-
}
|
|
524
|
-
}
|
|
525
|
-
let currentAction = action;
|
|
526
|
-
for (const rule of applicableRules) {
|
|
527
|
-
const result = rule.validate(currentAction, context);
|
|
528
|
-
if (!result.valid) {
|
|
529
|
-
return result;
|
|
530
|
-
}
|
|
531
|
-
if (result.correctedAction) {
|
|
532
|
-
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}`);
|
|
533
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
|
+
};
|
|
534
300
|
}
|
|
535
|
-
return {
|
|
536
|
-
valid: true,
|
|
537
|
-
correctedAction: currentAction !== action ? currentAction : void 0
|
|
538
|
-
};
|
|
539
301
|
};
|
|
540
|
-
const
|
|
541
|
-
rules
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
return Array.from(rules.values());
|
|
545
|
-
};
|
|
546
|
-
const removeRule = (ruleId) => {
|
|
547
|
-
return rules.delete(ruleId);
|
|
548
|
-
};
|
|
549
|
-
return {
|
|
550
|
-
validate,
|
|
551
|
-
registerRule,
|
|
552
|
-
listRules,
|
|
553
|
-
removeRule
|
|
302
|
+
const listRulesets = async () => {
|
|
303
|
+
const response = await fetch(`${apiUrl}/rules`);
|
|
304
|
+
if (!response.ok) return [];
|
|
305
|
+
return response.json();
|
|
554
306
|
};
|
|
307
|
+
return { validate, listRulesets };
|
|
555
308
|
};
|
|
556
|
-
var validateAction = (action,
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
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}`);
|
|
564
319
|
}
|
|
565
|
-
return
|
|
320
|
+
return response.json();
|
|
566
321
|
};
|
|
567
322
|
|
|
568
|
-
// src/
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
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;
|
|
577
340
|
};
|
|
578
341
|
};
|
|
579
|
-
var
|
|
580
|
-
|
|
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
|
+
};
|
|
581
351
|
};
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
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();
|
|
587
367
|
return {
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
name: parsed.name || "Unknown",
|
|
591
|
-
persona: parsed.persona,
|
|
592
|
-
state: parsed.state,
|
|
593
|
-
memories: parsed.memories || [],
|
|
594
|
-
signature: parsed.signature
|
|
368
|
+
sessionId: data.sessionId,
|
|
369
|
+
status: data.runStatus
|
|
595
370
|
};
|
|
596
371
|
};
|
|
597
|
-
var
|
|
598
|
-
const
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
createArweaveDataItem2 = imported.createArweaveDataItem;
|
|
606
|
-
} catch (e) {
|
|
607
|
-
throw new Error("Missing ANS-104 Arweave module. Rebuild the SDK to enable direct uploads.");
|
|
608
|
-
}
|
|
609
|
-
const jwk = typeof wallet === "string" ? JSON.parse(wallet) : wallet;
|
|
610
|
-
const dataToUpload = serializeSoul(soul);
|
|
611
|
-
const tags = [
|
|
612
|
-
{ name: "Content-Type", value: "application/json" },
|
|
613
|
-
{ name: "App-Name", value: "ForbocAI" },
|
|
614
|
-
{ name: "App-Version", value: "soul-1" }
|
|
615
|
-
];
|
|
616
|
-
const dataItem = await createArweaveDataItem2(dataToUpload, jwk, { tags });
|
|
617
|
-
const rawData = dataItem.raw;
|
|
618
|
-
if (!rawData) {
|
|
619
|
-
throw new Error("Failed to build ANS-104 data item");
|
|
620
|
-
}
|
|
621
|
-
const bundlerUrl = config.bundlerUrl || "https://upload.ardrive.io/v1/tx";
|
|
622
|
-
const gatewayUrl = config.gatewayUrl || "https://arweave.net";
|
|
623
|
-
try {
|
|
624
|
-
const response = await fetch(bundlerUrl, {
|
|
625
|
-
method: "POST",
|
|
626
|
-
headers: { "Content-Type": "application/octet-stream" },
|
|
627
|
-
body: rawData
|
|
628
|
-
});
|
|
629
|
-
if (!response.ok) {
|
|
630
|
-
const message = await response.text().catch(() => response.statusText);
|
|
631
|
-
throw new Error(message || response.statusText);
|
|
632
|
-
}
|
|
633
|
-
const responseText = await response.text();
|
|
634
|
-
let responseJson = null;
|
|
635
|
-
try {
|
|
636
|
-
responseJson = JSON.parse(responseText);
|
|
637
|
-
} catch {
|
|
638
|
-
responseJson = null;
|
|
639
|
-
}
|
|
640
|
-
const txId = responseJson?.id || responseJson?.dataItemId || responseJson?.txId || (typeof responseText === "string" && responseText.trim().length > 0 ? responseText.trim() : null) || dataItem.id;
|
|
641
|
-
if (!txId) {
|
|
642
|
-
throw new Error("Bundler response did not include a data item id");
|
|
643
|
-
}
|
|
644
|
-
return {
|
|
645
|
-
txId,
|
|
646
|
-
url: `${gatewayUrl}/${txId}`,
|
|
647
|
-
soul
|
|
648
|
-
};
|
|
649
|
-
} catch (e) {
|
|
650
|
-
throw new Error(`Failed to upload to Arweave: ${e}`);
|
|
651
|
-
}
|
|
652
|
-
};
|
|
653
|
-
var exportSoul = async (_agentId, soul, config = {}) => {
|
|
654
|
-
if (!config.walletJwk && !config.privateKey) {
|
|
655
|
-
throw new Error("walletJwk required for Arweave ANS-104 export");
|
|
656
|
-
}
|
|
657
|
-
return uploadToArweave(soul, config);
|
|
658
|
-
};
|
|
659
|
-
var importSoulFromArweave = async (txId, config = {}) => {
|
|
660
|
-
const gateway = config.gatewayUrl || "https://arweave.net";
|
|
661
|
-
try {
|
|
662
|
-
const response = await fetch(`${gateway}/${txId}`, {
|
|
663
|
-
method: "GET",
|
|
664
|
-
headers: { "Content-Type": "application/json" }
|
|
665
|
-
});
|
|
666
|
-
if (!response.ok) {
|
|
667
|
-
throw new Error(`Import failed: ${response.statusText}`);
|
|
668
|
-
}
|
|
669
|
-
const data = await response.json();
|
|
670
|
-
if (!data.id || !data.persona) {
|
|
671
|
-
throw new Error("Invalid soul data from Arweave");
|
|
672
|
-
}
|
|
673
|
-
return data;
|
|
674
|
-
} catch (e) {
|
|
675
|
-
throw new Error(`Failed to import Soul from TXID ${txId}: ${e}`);
|
|
676
|
-
}
|
|
677
|
-
};
|
|
678
|
-
var getSoulList = async (limit = 50, apiUrl) => {
|
|
679
|
-
const url = apiUrl || "https://api.forboc.ai";
|
|
680
|
-
try {
|
|
681
|
-
const response = await fetch(`${url}/souls?limit=${limit}`);
|
|
682
|
-
if (!response.ok) throw new Error(response.statusText);
|
|
683
|
-
const data = await response.json();
|
|
684
|
-
return data.souls.map((s) => {
|
|
685
|
-
const txId = s.txId || s.soulEntryTxId || s.cid;
|
|
686
|
-
const name = s.name || s.soulEntryName;
|
|
687
|
-
const agentId = s.agentId || s.soulEntryAgentId;
|
|
688
|
-
const exportedAt = s.exportedAt || s.soulEntryExportedAt;
|
|
689
|
-
const url2 = s.url || s.soulEntryArweaveUrl || `https://arweave.net/${txId}`;
|
|
690
|
-
return { txId, name, agentId, exportedAt, url: url2 };
|
|
691
|
-
});
|
|
692
|
-
} catch (e) {
|
|
693
|
-
return [];
|
|
694
|
-
}
|
|
695
|
-
};
|
|
696
|
-
var createSoulInstance = (id, name, persona, state, memories = []) => {
|
|
697
|
-
const soulData = createSoul(id, name, persona, state, memories);
|
|
698
|
-
const performExport = async (config) => {
|
|
699
|
-
return exportSoul(soulData.id, soulData, { ...config });
|
|
700
|
-
};
|
|
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();
|
|
701
380
|
return {
|
|
702
|
-
|
|
703
|
-
|
|
381
|
+
sessionId: data.ghostSessionId,
|
|
382
|
+
status: data.ghostStatus,
|
|
383
|
+
progress: data.ghostProgress,
|
|
384
|
+
startedAt: data.ghostStartedAt,
|
|
385
|
+
duration: data.ghostDuration,
|
|
386
|
+
errors: data.ghostErrors
|
|
704
387
|
};
|
|
705
388
|
};
|
|
706
|
-
var
|
|
707
|
-
const
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
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();
|
|
711
397
|
return {
|
|
712
|
-
|
|
713
|
-
|
|
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 || [])
|
|
714
413
|
};
|
|
715
414
|
};
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
const apiUrl = config.apiUrl || "https://api.forboc.ai";
|
|
720
|
-
try {
|
|
721
|
-
const response = await fetch(`${apiUrl}/ghost/run`, {
|
|
722
|
-
method: "POST",
|
|
723
|
-
headers: { "Content-Type": "application/json" },
|
|
724
|
-
body: JSON.stringify({
|
|
725
|
-
testSuite: config.testSuite,
|
|
726
|
-
duration: config.duration
|
|
727
|
-
})
|
|
728
|
-
});
|
|
729
|
-
if (!response.ok) {
|
|
730
|
-
throw new Error(`Failed to start Ghost session: ${response.statusText}`);
|
|
731
|
-
}
|
|
732
|
-
const data = await response.json();
|
|
733
|
-
return {
|
|
734
|
-
sessionId: data.sessionId,
|
|
735
|
-
status: data.runStatus
|
|
736
|
-
};
|
|
737
|
-
} catch (e) {
|
|
738
|
-
const mockId = `ghost_${Date.now()}_${Math.random().toString(36).substring(7)}`;
|
|
739
|
-
return {
|
|
740
|
-
sessionId: mockId,
|
|
741
|
-
status: "running"
|
|
742
|
-
};
|
|
743
|
-
}
|
|
744
|
-
};
|
|
745
|
-
var getGhostStatus = async (sessionId, apiUrl) => {
|
|
746
|
-
const url = apiUrl || "https://api.forboc.ai";
|
|
747
|
-
try {
|
|
748
|
-
const response = await fetch(`${url}/ghost/${sessionId}/status`, {
|
|
749
|
-
method: "GET",
|
|
750
|
-
headers: { "Content-Type": "application/json" }
|
|
751
|
-
});
|
|
752
|
-
if (!response.ok) {
|
|
753
|
-
throw new Error(`Failed to get Ghost status: ${response.statusText}`);
|
|
754
|
-
}
|
|
755
|
-
const data = await response.json();
|
|
756
|
-
return {
|
|
757
|
-
sessionId: data.ghostSessionId,
|
|
758
|
-
status: data.ghostStatus,
|
|
759
|
-
progress: data.ghostProgress,
|
|
760
|
-
startedAt: data.ghostStartedAt,
|
|
761
|
-
duration: data.ghostDuration,
|
|
762
|
-
errors: data.ghostErrors
|
|
763
|
-
};
|
|
764
|
-
} catch (e) {
|
|
765
|
-
return {
|
|
766
|
-
sessionId,
|
|
767
|
-
status: "running",
|
|
768
|
-
progress: Math.floor(Math.random() * 100),
|
|
769
|
-
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
770
|
-
duration: 60,
|
|
771
|
-
errors: 0
|
|
772
|
-
};
|
|
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`);
|
|
773
418
|
}
|
|
774
|
-
};
|
|
775
|
-
var getGhostResults = async (sessionId, apiUrl) => {
|
|
776
|
-
const url = apiUrl || "https://api.forboc.ai";
|
|
777
419
|
try {
|
|
778
|
-
const
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
});
|
|
782
|
-
if (!response.ok) {
|
|
783
|
-
throw new Error(`Failed to get Ghost results: ${response.statusText}`);
|
|
784
|
-
}
|
|
785
|
-
const data = await response.json();
|
|
786
|
-
return {
|
|
787
|
-
sessionId: data.resultsSessionId,
|
|
788
|
-
totalTests: data.resultsTotalTests,
|
|
789
|
-
passed: data.resultsPassed,
|
|
790
|
-
failed: data.resultsFailed,
|
|
791
|
-
skipped: data.resultsSkipped,
|
|
792
|
-
duration: data.resultsDuration,
|
|
793
|
-
tests: data.resultsTests.map((t) => ({
|
|
794
|
-
name: t.testName,
|
|
795
|
-
passed: t.testPassed,
|
|
796
|
-
duration: t.testDuration,
|
|
797
|
-
error: t.testError,
|
|
798
|
-
screenshot: t.testScreenshot
|
|
799
|
-
})),
|
|
800
|
-
coverage: data.resultsCoverage,
|
|
801
|
-
metrics: Object.fromEntries(data.resultsMetrics)
|
|
802
|
-
};
|
|
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`);
|
|
803
424
|
} catch (e) {
|
|
804
|
-
return {
|
|
805
|
-
sessionId,
|
|
806
|
-
totalTests: 5,
|
|
807
|
-
passed: 4,
|
|
808
|
-
failed: 1,
|
|
809
|
-
skipped: 0,
|
|
810
|
-
duration: 1245,
|
|
811
|
-
tests: [
|
|
812
|
-
{ name: "test.navigation", passed: true, duration: 150 },
|
|
813
|
-
{ name: "test.combat", passed: true, duration: 230 },
|
|
814
|
-
{ name: "test.dialogue", passed: false, duration: 450, error: "Timeout" }
|
|
815
|
-
],
|
|
816
|
-
coverage: 0.75,
|
|
817
|
-
metrics: {
|
|
818
|
-
avgFrameRate: 58.5,
|
|
819
|
-
memoryUsageMB: 512.3,
|
|
820
|
-
aiDecisionsPerSec: 15.2
|
|
821
|
-
}
|
|
822
|
-
};
|
|
823
425
|
}
|
|
426
|
+
await delay(pollIntervalMs);
|
|
427
|
+
return pollForCompletion(sessionId, pollIntervalMs, timeoutMs, startTime, apiUrl, onProgress);
|
|
824
428
|
};
|
|
825
|
-
var waitForGhostCompletion =
|
|
826
|
-
const startTime = Date.now();
|
|
827
|
-
while (Date.now() - startTime < timeoutMs) {
|
|
828
|
-
try {
|
|
829
|
-
const status = await getGhostStatus(sessionId, apiUrl);
|
|
830
|
-
if (onProgress) {
|
|
831
|
-
onProgress(status);
|
|
832
|
-
}
|
|
833
|
-
if (status.status === "completed") {
|
|
834
|
-
return getGhostResults(sessionId, apiUrl);
|
|
835
|
-
}
|
|
836
|
-
if (status.status === "failed") {
|
|
837
|
-
throw new Error(`Ghost session failed with ${status.errors} errors`);
|
|
838
|
-
}
|
|
839
|
-
} catch (e) {
|
|
840
|
-
}
|
|
841
|
-
await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
|
|
842
|
-
}
|
|
843
|
-
throw new Error(`Ghost session timed out after ${timeoutMs}ms`);
|
|
844
|
-
};
|
|
429
|
+
var waitForGhostCompletion = (sessionId, pollIntervalMs = 5e3, timeoutMs = 3e5, apiUrl, onProgress) => pollForCompletion(sessionId, pollIntervalMs, timeoutMs, Date.now(), apiUrl, onProgress);
|
|
845
430
|
var stopGhostSession = async (sessionId, apiUrl) => {
|
|
846
|
-
const url = apiUrl ||
|
|
431
|
+
const url = apiUrl || DEFAULT_API_URL;
|
|
847
432
|
try {
|
|
848
|
-
const response = await fetch(`${url}/ghost/${sessionId}/stop`, {
|
|
849
|
-
|
|
850
|
-
headers: { "Content-Type": "application/json" }
|
|
851
|
-
});
|
|
852
|
-
if (!response.ok) {
|
|
853
|
-
throw new Error(`Failed to stop Ghost session: ${response.statusText}`);
|
|
854
|
-
}
|
|
855
|
-
const data = await response.json();
|
|
856
|
-
return {
|
|
857
|
-
stopped: true,
|
|
858
|
-
status: data.status || "stopped"
|
|
859
|
-
};
|
|
433
|
+
const response = await fetch(`${url}/ghost/${sessionId}/stop`, { method: "POST" });
|
|
434
|
+
return { stopped: response.ok };
|
|
860
435
|
} catch (e) {
|
|
861
|
-
return {
|
|
862
|
-
stopped: true,
|
|
863
|
-
status: "stopped"
|
|
864
|
-
};
|
|
436
|
+
return { stopped: true };
|
|
865
437
|
}
|
|
866
438
|
};
|
|
867
439
|
var getGhostHistory = async (limit = 10, apiUrl) => {
|
|
868
|
-
const url = apiUrl ||
|
|
440
|
+
const url = apiUrl || DEFAULT_API_URL;
|
|
869
441
|
try {
|
|
870
|
-
const response = await fetch(`${url}/ghost/history?limit=${limit}
|
|
871
|
-
|
|
872
|
-
headers: { "Content-Type": "application/json" }
|
|
873
|
-
});
|
|
874
|
-
if (!response.ok) {
|
|
875
|
-
throw new Error(`Failed to get Ghost history: ${response.statusText}`);
|
|
876
|
-
}
|
|
442
|
+
const response = await fetch(`${url}/ghost/history?limit=${limit}`);
|
|
443
|
+
if (!response.ok) return [];
|
|
877
444
|
const data = await response.json();
|
|
878
445
|
return data.sessions.map((s) => ({
|
|
879
446
|
sessionId: s.sessionId,
|
|
@@ -888,50 +455,25 @@ var getGhostHistory = async (limit = 10, apiUrl) => {
|
|
|
888
455
|
}
|
|
889
456
|
};
|
|
890
457
|
var createGhost = (config) => {
|
|
891
|
-
let
|
|
892
|
-
const apiUrl = config.apiUrl ||
|
|
458
|
+
let _sessionId = null;
|
|
459
|
+
const apiUrl = config.apiUrl || DEFAULT_API_URL;
|
|
893
460
|
const run = async () => {
|
|
894
461
|
const result = await startGhostSession(config);
|
|
895
|
-
|
|
896
|
-
return
|
|
462
|
+
_sessionId = result.sessionId;
|
|
463
|
+
return _sessionId;
|
|
897
464
|
};
|
|
898
|
-
const
|
|
899
|
-
if (!
|
|
900
|
-
|
|
901
|
-
}
|
|
902
|
-
return getGhostStatus(sessionId, apiUrl);
|
|
903
|
-
};
|
|
904
|
-
const results = async () => {
|
|
905
|
-
if (!sessionId) {
|
|
906
|
-
throw new Error("Ghost session not started");
|
|
907
|
-
}
|
|
908
|
-
return getGhostResults(sessionId, apiUrl);
|
|
465
|
+
const ensureSessionId = () => {
|
|
466
|
+
if (!_sessionId) throw new Error("Ghost session not started");
|
|
467
|
+
return _sessionId;
|
|
909
468
|
};
|
|
469
|
+
const status = async () => getGhostStatus(ensureSessionId(), apiUrl);
|
|
470
|
+
const results = async () => getGhostResults(ensureSessionId(), apiUrl);
|
|
910
471
|
const stop = async () => {
|
|
911
|
-
if (
|
|
912
|
-
|
|
913
|
-
}
|
|
914
|
-
sessionId = null;
|
|
915
|
-
};
|
|
916
|
-
const waitForCompletion = async (pollIntervalMs, timeoutMs, onProgress) => {
|
|
917
|
-
if (!sessionId) {
|
|
918
|
-
throw new Error("Ghost session not started");
|
|
919
|
-
}
|
|
920
|
-
return waitForGhostCompletion(
|
|
921
|
-
sessionId,
|
|
922
|
-
pollIntervalMs,
|
|
923
|
-
timeoutMs,
|
|
924
|
-
apiUrl,
|
|
925
|
-
onProgress
|
|
926
|
-
);
|
|
927
|
-
};
|
|
928
|
-
return {
|
|
929
|
-
run,
|
|
930
|
-
status,
|
|
931
|
-
results,
|
|
932
|
-
stop,
|
|
933
|
-
waitForCompletion
|
|
472
|
+
if (_sessionId) await stopGhostSession(_sessionId, apiUrl);
|
|
473
|
+
_sessionId = null;
|
|
934
474
|
};
|
|
475
|
+
const waitForCompletion = (pollIntervalMs, timeoutMs, onProgress) => waitForGhostCompletion(ensureSessionId(), pollIntervalMs, timeoutMs, apiUrl, onProgress);
|
|
476
|
+
return { run, status, results, stop, waitForCompletion };
|
|
935
477
|
};
|
|
936
478
|
|
|
937
479
|
// src/cortex-remote.ts
|
|
@@ -964,249 +506,31 @@ var createRemoteCortex = (apiUrl, cortexId = "local", apiKey) => {
|
|
|
964
506
|
};
|
|
965
507
|
|
|
966
508
|
// src/stream.ts
|
|
967
|
-
async
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
let fullText = "";
|
|
982
|
-
for await (const chunk of stream) {
|
|
983
|
-
fullText += chunk;
|
|
984
|
-
onChunk(chunk);
|
|
985
|
-
}
|
|
986
|
-
return fullText;
|
|
987
|
-
}
|
|
988
|
-
async function streamFromCortexWithDelay(cortex, prompt, onChunk, options) {
|
|
989
|
-
const { delayMs = 30, ...completionOptions } = options ?? {};
|
|
990
|
-
const stream = cortex.completeStream(prompt, completionOptions);
|
|
991
|
-
let fullText = "";
|
|
992
|
-
for await (const chunk of stream) {
|
|
993
|
-
fullText += chunk;
|
|
994
|
-
onChunk(chunk);
|
|
995
|
-
if (delayMs > 0) {
|
|
996
|
-
await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
997
|
-
}
|
|
998
|
-
}
|
|
999
|
-
return fullText;
|
|
1000
|
-
}
|
|
1001
|
-
|
|
1002
|
-
// src/presets/index.ts
|
|
1003
|
-
var presets_exports = {};
|
|
1004
|
-
__export(presets_exports, {
|
|
1005
|
-
RPG_MEMORY_TYPES: () => RPG_MEMORY_TYPES,
|
|
1006
|
-
RPG_MOODS: () => RPG_MOODS,
|
|
1007
|
-
attackRule: () => attackRule,
|
|
1008
|
-
createRPGState: () => createRPGState,
|
|
1009
|
-
interactRule: () => interactRule,
|
|
1010
|
-
movementRule: () => movementRule,
|
|
1011
|
-
puzzleRules: () => puzzleRules,
|
|
1012
|
-
resourceRule: () => resourceRule,
|
|
1013
|
-
rpgRules: () => rpgRules,
|
|
1014
|
-
socialRules: () => socialRules,
|
|
1015
|
-
spatialRules: () => spatialRules,
|
|
1016
|
-
speakRule: () => speakRule
|
|
1017
|
-
});
|
|
1018
|
-
|
|
1019
|
-
// src/presets/rpg.ts
|
|
1020
|
-
var RPG_MOODS = {
|
|
1021
|
-
hostile: "hostile",
|
|
1022
|
-
suspicious: "suspicious",
|
|
1023
|
-
neutral: "neutral",
|
|
1024
|
-
friendly: "friendly",
|
|
1025
|
-
loyal: "loyal"
|
|
1026
|
-
};
|
|
1027
|
-
var RPG_MEMORY_TYPES = {
|
|
1028
|
-
observation: "observation",
|
|
1029
|
-
experience: "experience",
|
|
1030
|
-
knowledge: "knowledge",
|
|
1031
|
-
emotion: "emotion"
|
|
1032
|
-
};
|
|
1033
|
-
var createRPGState = (partial) => {
|
|
1034
|
-
return {
|
|
1035
|
-
inventory: partial?.inventory ?? [],
|
|
1036
|
-
hp: partial?.hp ?? 100,
|
|
1037
|
-
mana: partial?.mana ?? 100,
|
|
1038
|
-
skills: partial?.skills ?? {},
|
|
1039
|
-
relationships: partial?.relationships ?? {},
|
|
1040
|
-
mood: partial?.mood ?? "neutral",
|
|
1041
|
-
...partial
|
|
1042
|
-
};
|
|
1043
|
-
};
|
|
1044
|
-
var movementRule = {
|
|
1045
|
-
id: "core.movement",
|
|
1046
|
-
name: "Movement Validation",
|
|
1047
|
-
description: "Ensures MOVE actions have valid x,y coordinates",
|
|
1048
|
-
actionTypes: ["MOVE", "move"],
|
|
1049
|
-
validate: (action, context) => {
|
|
1050
|
-
const payload = action.payload || {};
|
|
1051
|
-
const target = payload.target;
|
|
1052
|
-
if (!target || typeof target.x !== "number" || typeof target.y !== "number") {
|
|
1053
|
-
return {
|
|
1054
|
-
valid: false,
|
|
1055
|
-
reason: "MOVE action must have target with numeric x,y coordinates",
|
|
1056
|
-
correctedAction: {
|
|
1057
|
-
...action,
|
|
1058
|
-
type: "IDLE",
|
|
1059
|
-
reason: "Invalid MOVE target - defaulting to IDLE"
|
|
1060
|
-
}
|
|
1061
|
-
};
|
|
1062
|
-
}
|
|
1063
|
-
const world = context.worldState || {};
|
|
1064
|
-
const maxX = world.maxX || Infinity;
|
|
1065
|
-
const maxY = world.maxY || Infinity;
|
|
1066
|
-
if (target.x < 0 || target.x > maxX || target.y < 0 || target.y > maxY) {
|
|
1067
|
-
return {
|
|
1068
|
-
valid: false,
|
|
1069
|
-
reason: `MOVE target (${target.x}, ${target.y}) is out of bounds`,
|
|
1070
|
-
correctedAction: {
|
|
1071
|
-
...action,
|
|
1072
|
-
payload: {
|
|
1073
|
-
...payload,
|
|
1074
|
-
target: {
|
|
1075
|
-
x: Math.max(0, Math.min(maxX, target.x)),
|
|
1076
|
-
y: Math.max(0, Math.min(maxY, target.y))
|
|
1077
|
-
}
|
|
1078
|
-
}
|
|
1079
|
-
}
|
|
1080
|
-
};
|
|
1081
|
-
}
|
|
1082
|
-
return { valid: true };
|
|
1083
|
-
}
|
|
1084
|
-
};
|
|
1085
|
-
var attackRule = {
|
|
1086
|
-
id: "core.attack",
|
|
1087
|
-
name: "Attack Validation",
|
|
1088
|
-
description: "Ensures ATTACK actions have valid targetId",
|
|
1089
|
-
actionTypes: ["ATTACK", "attack"],
|
|
1090
|
-
validate: (action, context) => {
|
|
1091
|
-
if (!action.target && !action.payload?.targetId) {
|
|
1092
|
-
return {
|
|
1093
|
-
valid: false,
|
|
1094
|
-
reason: "ATTACK action must have a target or targetId",
|
|
1095
|
-
correctedAction: {
|
|
1096
|
-
...action,
|
|
1097
|
-
type: "IDLE",
|
|
1098
|
-
reason: "Invalid ATTACK - no target specified"
|
|
1099
|
-
}
|
|
1100
|
-
};
|
|
1101
|
-
}
|
|
1102
|
-
const world = context.worldState || {};
|
|
1103
|
-
const entities = world.entities || [];
|
|
1104
|
-
const targetId = action.target || action.payload?.targetId;
|
|
1105
|
-
if (entities.length > 0 && !entities.includes(targetId)) {
|
|
1106
|
-
return {
|
|
1107
|
-
valid: false,
|
|
1108
|
-
reason: `ATTACK target '${targetId}' does not exist in world`,
|
|
1109
|
-
correctedAction: {
|
|
1110
|
-
...action,
|
|
1111
|
-
type: "IDLE",
|
|
1112
|
-
reason: "Target not found"
|
|
1113
|
-
}
|
|
1114
|
-
};
|
|
1115
|
-
}
|
|
1116
|
-
return { valid: true };
|
|
1117
|
-
}
|
|
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
|
+
});
|
|
1118
523
|
};
|
|
1119
|
-
var
|
|
1120
|
-
|
|
1121
|
-
name: "Interact Validation",
|
|
1122
|
-
description: "Ensures INTERACT actions have valid objectId",
|
|
1123
|
-
actionTypes: ["INTERACT", "interact"],
|
|
1124
|
-
validate: (action, context) => {
|
|
1125
|
-
if (!action.target && !action.payload?.objectId) {
|
|
1126
|
-
return {
|
|
1127
|
-
valid: false,
|
|
1128
|
-
reason: "INTERACT action must have objectId",
|
|
1129
|
-
correctedAction: {
|
|
1130
|
-
...action,
|
|
1131
|
-
type: "IDLE",
|
|
1132
|
-
reason: "Invalid INTERACT - no object specified"
|
|
1133
|
-
}
|
|
1134
|
-
};
|
|
1135
|
-
}
|
|
1136
|
-
return { valid: true };
|
|
1137
|
-
}
|
|
524
|
+
var streamFromCortex = async (cortex, prompt, onChunk, options) => {
|
|
525
|
+
return consumeStream(cortex.completeStream(prompt, options), onChunk);
|
|
1138
526
|
};
|
|
1139
|
-
var
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
description: "Ensures SPEAK actions have non-empty text",
|
|
1143
|
-
actionTypes: ["SPEAK", "speak"],
|
|
1144
|
-
validate: (action, context) => {
|
|
1145
|
-
const text = action.payload?.text;
|
|
1146
|
-
if (!text || text.trim().length === 0) {
|
|
1147
|
-
return {
|
|
1148
|
-
valid: false,
|
|
1149
|
-
reason: "SPEAK action must have non-empty text",
|
|
1150
|
-
correctedAction: {
|
|
1151
|
-
...action,
|
|
1152
|
-
type: "IDLE",
|
|
1153
|
-
reason: "Empty speech - defaulting to IDLE"
|
|
1154
|
-
}
|
|
1155
|
-
};
|
|
1156
|
-
}
|
|
1157
|
-
const maxLength = context.constraints?.maxSpeechLength || 1e3;
|
|
1158
|
-
if (text.length > maxLength) {
|
|
1159
|
-
return {
|
|
1160
|
-
valid: true,
|
|
1161
|
-
reason: `Speech truncated to ${maxLength} characters`,
|
|
1162
|
-
correctedAction: {
|
|
1163
|
-
...action,
|
|
1164
|
-
payload: {
|
|
1165
|
-
...action.payload,
|
|
1166
|
-
text: text.substring(0, maxLength)
|
|
1167
|
-
}
|
|
1168
|
-
}
|
|
1169
|
-
};
|
|
1170
|
-
}
|
|
1171
|
-
return { valid: true };
|
|
1172
|
-
}
|
|
1173
|
-
};
|
|
1174
|
-
var resourceRule = {
|
|
1175
|
-
id: "core.resources",
|
|
1176
|
-
name: "Resource Validation",
|
|
1177
|
-
description: "Ensures agent has required resources for action",
|
|
1178
|
-
actionTypes: ["ATTACK", "CAST", "USE_ITEM"],
|
|
1179
|
-
validate: (action, context) => {
|
|
1180
|
-
const agent = context.agentState || {};
|
|
1181
|
-
const hp = agent.hp ?? 100;
|
|
1182
|
-
const mana = agent.mana ?? 100;
|
|
1183
|
-
if (hp <= 0) {
|
|
1184
|
-
return {
|
|
1185
|
-
valid: false,
|
|
1186
|
-
reason: "Agent is dead and cannot perform actions",
|
|
1187
|
-
correctedAction: { ...action, type: "IDLE", reason: "Agent dead" }
|
|
1188
|
-
};
|
|
1189
|
-
}
|
|
1190
|
-
if (action.type === "CAST" || action.type === "cast") {
|
|
1191
|
-
const manaCost = action.payload?.manaCost || 10;
|
|
1192
|
-
if (mana < manaCost) {
|
|
1193
|
-
return {
|
|
1194
|
-
valid: false,
|
|
1195
|
-
reason: `Insufficient mana: need ${manaCost}, have ${mana}`,
|
|
1196
|
-
correctedAction: { ...action, type: "IDLE", reason: "Not enough mana" }
|
|
1197
|
-
};
|
|
1198
|
-
}
|
|
1199
|
-
}
|
|
1200
|
-
return { valid: true };
|
|
1201
|
-
}
|
|
527
|
+
var streamFromCortexWithDelay = async (cortex, prompt, onChunk, options) => {
|
|
528
|
+
const { delayMs = 30, ...completionOptions } = options ?? {};
|
|
529
|
+
return consumeStream(cortex.completeStream(prompt, completionOptions), onChunk, "", delayMs);
|
|
1202
530
|
};
|
|
1203
|
-
var rpgRules = [movementRule, attackRule, interactRule, speakRule, resourceRule];
|
|
1204
|
-
var spatialRules = [movementRule];
|
|
1205
|
-
var socialRules = [speakRule, interactRule];
|
|
1206
|
-
var puzzleRules = [movementRule, interactRule];
|
|
1207
531
|
|
|
1208
532
|
// src/index.ts
|
|
1209
|
-
var SDK_VERSION = "0.5.
|
|
533
|
+
var SDK_VERSION = "0.5.9";
|
|
1210
534
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1211
535
|
0 && (module.exports = {
|
|
1212
536
|
SDK_VERSION,
|
|
@@ -1217,6 +541,7 @@ var SDK_VERSION = "0.5.7";
|
|
|
1217
541
|
createRemoteCortex,
|
|
1218
542
|
createSoul,
|
|
1219
543
|
createSoulInstance,
|
|
544
|
+
delay,
|
|
1220
545
|
deserializeSoul,
|
|
1221
546
|
exportSoul,
|
|
1222
547
|
exportToSoul,
|
|
@@ -1226,7 +551,10 @@ var SDK_VERSION = "0.5.7";
|
|
|
1226
551
|
getGhostStatus,
|
|
1227
552
|
getSoulList,
|
|
1228
553
|
importSoulFromArweave,
|
|
1229
|
-
|
|
554
|
+
loadPreset,
|
|
555
|
+
memoise,
|
|
556
|
+
memoiseAsync,
|
|
557
|
+
pipe,
|
|
1230
558
|
serializeSoul,
|
|
1231
559
|
startGhostSession,
|
|
1232
560
|
stopGhostSession,
|
|
@@ -1235,7 +563,6 @@ var SDK_VERSION = "0.5.7";
|
|
|
1235
563
|
streamToCallback,
|
|
1236
564
|
streamToString,
|
|
1237
565
|
updateAgentState,
|
|
1238
|
-
uploadToArweave,
|
|
1239
566
|
validateAction,
|
|
1240
567
|
validateSoul,
|
|
1241
568
|
waitForGhostCompletion
|