@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/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/ans104.ts
34
- var ans104_exports = {};
35
- __export(ans104_exports, {
36
- createArweaveDataItem: () => createArweaveDataItem
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 import_base64url, import_buffer, import_crypto, import_pem, SIGNATURE_TYPE_ARWEAVE, SIGNATURE_LENGTH, OWNER_LENGTH, MAX_TAG_BYTES, stringToBuffer, concatBuffers, longToNByteArray, longTo8ByteArray, shortTo2ByteArray, AVSCTap, serializeTags, hash, deepHash, deepHashChunks, getSignatureData, signData, getOwner, getPem, createArweaveDataItem;
39
- var init_ans104 = __esm({
40
- "src/ans104.ts"() {
35
+ var createSoul, serializeSoul, deserializeSoul, exportSoul, importSoulFromArweave, getSoulList, createSoulInstance, validateSoul;
36
+ var init_soul = __esm({
37
+ "src/soul.ts"() {
41
38
  "use strict";
42
- import_base64url = __toESM(require("base64url"));
43
- import_buffer = require("buffer");
44
- import_crypto = require("crypto");
45
- import_pem = require("arweave/node/lib/crypto/pem");
46
- SIGNATURE_TYPE_ARWEAVE = 1;
47
- SIGNATURE_LENGTH = 512;
48
- OWNER_LENGTH = 512;
49
- MAX_TAG_BYTES = 4096;
50
- stringToBuffer = (value) => import_buffer.Buffer.from(value);
51
- concatBuffers = (buffers) => import_buffer.Buffer.concat(buffers);
52
- longToNByteArray = (bytes, long) => {
53
- const byteArray = new Uint8Array(bytes);
54
- if (long < 0) throw new Error("Array is unsigned, cannot represent -ve numbers");
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
- const hashPair = concatBuffers([acc, await deepHash(chunks[0])]);
177
- const newAcc = hash(hashPair, "SHA-384");
178
- return deepHashChunks(chunks.slice(1), newAcc);
179
- };
180
- getSignatureData = async (signatureType, rawOwner, rawTarget, rawAnchor, rawTags, rawData) => {
181
- return deepHash([
182
- stringToBuffer("dataitem"),
183
- stringToBuffer("1"),
184
- stringToBuffer(signatureType.toString()),
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
- signData = async (pemKey, message) => {
193
- return (0, import_crypto.createSign)("sha256").update(message).sign({
194
- key: pemKey,
195
- padding: import_crypto.constants.RSA_PKCS1_PSS_PADDING
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
- getOwner = (jwk) => {
199
- return import_base64url.default.toBuffer(jwk.n);
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
- getPem = (jwk) => {
202
- const pem = (0, import_pem.jwkTopem)(jwk);
203
- return typeof pem === "string" ? pem : pem.toString();
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
- createArweaveDataItem = async (data, jwk, opts) => {
206
- const rawOwner = getOwner(jwk);
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
- id: import_base64url.default.encode(id),
257
- raw: bytes
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
- presets: () => presets_exports,
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
- return { ...partial };
302
- };
303
- var updateAgentState = (currentState, updates) => {
304
- return {
305
- ...currentState,
306
- ...updates
307
- };
308
- };
309
- var exportToSoul = (agentId, name, persona, state, memories) => {
310
- return {
311
- id: agentId,
312
- version: "1.0.0",
313
- name,
314
- persona,
315
- memories: [...memories],
316
- state: { ...state }
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 state = createInitialState(config.initialState);
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 getAgentState = () => {
326
- return { ...state };
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 = getAgentState();
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(directiveBody)
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
- let recalledMemories = [];
348
- if (config.memory && typeof config.memory.recall === "function") {
349
- try {
350
- const rawMemories = await config.memory.recall(
351
- directiveData.memoryRecall.query,
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(contextBody)
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(verdictBody)
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 && typeof config.memory.store === "function" && verdictData.memoryStore) {
405
- for (const instruction of verdictData.memoryStore) {
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 && Object.keys(verdictData.stateDelta).length > 0) {
410
- state = updateAgentState(state, verdictData.stateDelta);
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(speakBody)
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 reply = speak;
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
- let exportedMemories = [];
445
- if (config.memory && typeof config.memory.export === "function") {
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
- return {
455
- process,
456
- speak,
457
- reply,
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 && typeof memory.import === "function") {
472
- try {
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 effectiveConfig = {
484
- strictMode: config.strictMode ?? false,
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 applicableRules = Array.from(rules.values()).filter(
511
- (rule) => rule.actionTypes.some(
512
- (t) => t.toLowerCase() === action.type.toLowerCase()
513
- )
514
- );
515
- if (effectiveConfig.strictMode && applicableRules.length === 0) {
516
- const safeTypes = ["IDLE", "idle", "WAIT", "wait"];
517
- if (!safeTypes.includes(action.type)) {
518
- return {
519
- valid: false,
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 registerRule = (rule) => {
541
- rules.set(rule.id, rule);
542
- };
543
- const listRules = () => {
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, rules, context = {}) => {
557
- for (const rule of rules) {
558
- if (rule.actionTypes.some((t) => t.toLowerCase() === action.type.toLowerCase())) {
559
- const result = rule.validate(action, context);
560
- if (!result.valid) {
561
- return result;
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 { valid: true };
320
+ return response.json();
566
321
  };
567
322
 
568
- // src/soul.ts
569
- var createSoul = (id, name, persona, state, memories = []) => {
570
- return {
571
- id,
572
- version: "1.0.0",
573
- name,
574
- persona,
575
- state: { ...state },
576
- memories: [...memories]
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 serializeSoul = (soul) => {
580
- return JSON.stringify(soul, null, 2);
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
- var deserializeSoul = (json) => {
583
- const parsed = JSON.parse(json);
584
- if (!parsed.id || !parsed.persona || !parsed.state) {
585
- throw new Error("Invalid Soul format: missing required fields");
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
- id: parsed.id,
589
- version: parsed.version || "1.0.0",
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 uploadToArweave = async (soul, config) => {
598
- const wallet = config.walletJwk || config.privateKey;
599
- if (!wallet) {
600
- throw new Error("Arweave wallet JWK required for direct upload");
601
- }
602
- let createArweaveDataItem2;
603
- try {
604
- const imported = await Promise.resolve().then(() => (init_ans104(), ans104_exports));
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
- export: performExport,
703
- toJSON: () => ({ ...soulData })
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 validateSoul = (soul) => {
707
- const errors = [];
708
- if (!soul.id) errors.push("Missing id");
709
- if (!soul.persona) errors.push("Missing persona");
710
- if (!soul.state) errors.push("Missing state");
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
- valid: errors.length === 0,
713
- errors
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
- // src/ghost.ts
718
- var startGhostSession = async (config) => {
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 response = await fetch(`${url}/ghost/${sessionId}/results`, {
779
- method: "GET",
780
- headers: { "Content-Type": "application/json" }
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 = async (sessionId, pollIntervalMs = 5e3, timeoutMs = 3e5, apiUrl, onProgress) => {
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 || "https://api.forboc.ai";
431
+ const url = apiUrl || DEFAULT_API_URL;
847
432
  try {
848
- const response = await fetch(`${url}/ghost/${sessionId}/stop`, {
849
- method: "POST",
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 || "https://api.forboc.ai";
440
+ const url = apiUrl || DEFAULT_API_URL;
869
441
  try {
870
- const response = await fetch(`${url}/ghost/history?limit=${limit}`, {
871
- method: "GET",
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 sessionId = null;
892
- const apiUrl = config.apiUrl || "https://api.forboc.ai";
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
- sessionId = result.sessionId;
896
- return sessionId;
462
+ _sessionId = result.sessionId;
463
+ return _sessionId;
897
464
  };
898
- const status = async () => {
899
- if (!sessionId) {
900
- throw new Error("Ghost session not started");
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 (sessionId) {
912
- await stopGhostSession(sessionId, apiUrl);
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 function streamToCallback(stream, onChunk) {
968
- for await (const chunk of stream) {
969
- onChunk(chunk);
970
- }
971
- }
972
- async function streamToString(stream) {
973
- let fullText = "";
974
- for await (const chunk of stream) {
975
- fullText += chunk;
976
- }
977
- return fullText;
978
- }
979
- async function streamFromCortex(cortex, prompt, onChunk, options) {
980
- const stream = cortex.completeStream(prompt, options);
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 interactRule = {
1120
- id: "core.interact",
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 speakRule = {
1140
- id: "core.speak",
1141
- name: "Speak Validation",
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.7";
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
- presets,
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