@forbocai/core 0.6.1 → 0.6.3
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.d.mts +592 -21
- package/dist/index.d.ts +592 -21
- package/dist/index.js +417 -113
- package/dist/index.mjs +415 -113
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -49,6 +49,21 @@ var sdkApi = createApi({
|
|
|
49
49
|
transformResponse: (response) => response
|
|
50
50
|
}),
|
|
51
51
|
// NPC Endpoints
|
|
52
|
+
/**
|
|
53
|
+
* User Story: As the SDK protocol loop, I need a single process endpoint
|
|
54
|
+
* that returns one atomic instruction per turn while echoing full tape state.
|
|
55
|
+
* ᚹ one hop in, one hop out, like passing a lit shard through vacuum.
|
|
56
|
+
*/
|
|
57
|
+
postNpcProcess: builder.mutation({
|
|
58
|
+
query: ({ npcId, request, apiUrl, apiKey }) => ({
|
|
59
|
+
url: `${apiUrl}/npcs/${npcId}/process`,
|
|
60
|
+
method: "POST",
|
|
61
|
+
headers: apiKey ? { "Authorization": `Bearer ${apiKey}` } : {},
|
|
62
|
+
body: request
|
|
63
|
+
}),
|
|
64
|
+
invalidatesTags: (result, error, { npcId }) => [{ type: "NPC", id: npcId }],
|
|
65
|
+
transformResponse: (response) => response
|
|
66
|
+
}),
|
|
52
67
|
postDirective: builder.mutation({
|
|
53
68
|
query: ({ npcId, request, apiUrl, apiKey }) => ({
|
|
54
69
|
url: `${apiUrl}/npcs/${npcId}/directive`,
|
|
@@ -190,6 +205,16 @@ var sdkApi = createApi({
|
|
|
190
205
|
invalidatesTags: ["Soul"],
|
|
191
206
|
transformResponse: (response) => response
|
|
192
207
|
}),
|
|
208
|
+
postSoulExportConfirm: builder.mutation({
|
|
209
|
+
query: ({ npcId, request, apiUrl, apiKey }) => ({
|
|
210
|
+
url: `${apiUrl}/npcs/${npcId}/soul/confirm`,
|
|
211
|
+
method: "POST",
|
|
212
|
+
headers: apiKey ? { "Authorization": `Bearer ${apiKey}` } : {},
|
|
213
|
+
body: request
|
|
214
|
+
}),
|
|
215
|
+
invalidatesTags: ["Soul"],
|
|
216
|
+
transformResponse: (response) => response
|
|
217
|
+
}),
|
|
193
218
|
getSoulImport: builder.query({
|
|
194
219
|
query: ({ txId, apiUrl, apiKey }) => ({
|
|
195
220
|
url: `${apiUrl}/souls/${txId}`,
|
|
@@ -298,6 +323,16 @@ var sdkApi = createApi({
|
|
|
298
323
|
invalidatesTags: ["NPC"],
|
|
299
324
|
transformResponse: (response) => response
|
|
300
325
|
}),
|
|
326
|
+
postNpcImportConfirm: builder.mutation({
|
|
327
|
+
query: ({ request, apiUrl, apiKey }) => ({
|
|
328
|
+
url: `${apiUrl}/npcs/import/confirm`,
|
|
329
|
+
method: "POST",
|
|
330
|
+
headers: apiKey ? { "Authorization": `Bearer ${apiKey}` } : {},
|
|
331
|
+
body: request
|
|
332
|
+
}),
|
|
333
|
+
invalidatesTags: ["NPC"],
|
|
334
|
+
transformResponse: (response) => response
|
|
335
|
+
}),
|
|
301
336
|
// Cortex Remote Endpoint
|
|
302
337
|
postCortexComplete: builder.mutation({
|
|
303
338
|
query: ({ cortexId, prompt, options, apiUrl, apiKey }) => ({
|
|
@@ -317,6 +352,25 @@ var sdkApi = createApi({
|
|
|
317
352
|
})
|
|
318
353
|
});
|
|
319
354
|
|
|
355
|
+
// src/errors.ts
|
|
356
|
+
var extractThunkErrorMessage = (error, fallback) => {
|
|
357
|
+
if (typeof error === "string") return error;
|
|
358
|
+
if (error && typeof error === "object") {
|
|
359
|
+
const e = error;
|
|
360
|
+
if (typeof e.data === "object" && e.data?.message) return String(e.data.message);
|
|
361
|
+
if (typeof e.data === "string") return e.data;
|
|
362
|
+
if (e.message) return e.message;
|
|
363
|
+
if (e.error) return e.error;
|
|
364
|
+
}
|
|
365
|
+
return fallback;
|
|
366
|
+
};
|
|
367
|
+
var requireApiKeyGuidance = (apiUrl, apiKey) => {
|
|
368
|
+
const normalized = apiUrl.toLowerCase();
|
|
369
|
+
if (normalized.includes("api.forboc.ai") && !apiKey) {
|
|
370
|
+
throw new Error("Missing API key. Set FORBOCAI_API_KEY (or run `forboc config set apiKey <key>`) for production API calls.");
|
|
371
|
+
}
|
|
372
|
+
};
|
|
373
|
+
|
|
320
374
|
// src/bridgeSlice.ts
|
|
321
375
|
var initialState = {
|
|
322
376
|
activePresets: [],
|
|
@@ -331,6 +385,7 @@ var validateBridgeThunk = createAsyncThunk(
|
|
|
331
385
|
async ({ action, context, npcId, apiUrl, apiKey }, { dispatch: dispatch2, rejectWithValue }) => {
|
|
332
386
|
try {
|
|
333
387
|
const url = apiUrl || "https://api.forboc.ai";
|
|
388
|
+
requireApiKeyGuidance(url, apiKey);
|
|
334
389
|
const data = await dispatch2(sdkApi.endpoints.postBridgeValidate.initiate({
|
|
335
390
|
request: { action, context },
|
|
336
391
|
npcId,
|
|
@@ -338,8 +393,8 @@ var validateBridgeThunk = createAsyncThunk(
|
|
|
338
393
|
apiKey
|
|
339
394
|
})).unwrap();
|
|
340
395
|
return data;
|
|
341
|
-
} catch (
|
|
342
|
-
return rejectWithValue(
|
|
396
|
+
} catch (error) {
|
|
397
|
+
return rejectWithValue(extractThunkErrorMessage(error, "Bridge validation failed"));
|
|
343
398
|
}
|
|
344
399
|
}
|
|
345
400
|
);
|
|
@@ -348,9 +403,10 @@ var loadBridgePresetThunk = createAsyncThunk(
|
|
|
348
403
|
async ({ presetName, apiUrl, apiKey }, { dispatch: dispatch2, rejectWithValue }) => {
|
|
349
404
|
try {
|
|
350
405
|
const url = apiUrl || "https://api.forboc.ai";
|
|
406
|
+
requireApiKeyGuidance(url, apiKey);
|
|
351
407
|
return await dispatch2(sdkApi.endpoints.postBridgePreset.initiate({ presetName, apiUrl: url, apiKey })).unwrap();
|
|
352
|
-
} catch (
|
|
353
|
-
return rejectWithValue(
|
|
408
|
+
} catch (error) {
|
|
409
|
+
return rejectWithValue(extractThunkErrorMessage(error, "Failed to load preset"));
|
|
354
410
|
}
|
|
355
411
|
}
|
|
356
412
|
);
|
|
@@ -359,9 +415,10 @@ var getBridgeRulesThunk = createAsyncThunk(
|
|
|
359
415
|
async ({ apiUrl, apiKey }, { dispatch: dispatch2, rejectWithValue }) => {
|
|
360
416
|
try {
|
|
361
417
|
const url = apiUrl || "https://api.forboc.ai";
|
|
418
|
+
requireApiKeyGuidance(url, apiKey);
|
|
362
419
|
return await dispatch2(sdkApi.endpoints.getBridgeRules.initiate({ apiUrl: url, apiKey })).unwrap();
|
|
363
|
-
} catch (
|
|
364
|
-
return rejectWithValue(
|
|
420
|
+
} catch (error) {
|
|
421
|
+
return rejectWithValue(extractThunkErrorMessage(error, "Failed to list bridge rules"));
|
|
365
422
|
}
|
|
366
423
|
}
|
|
367
424
|
);
|
|
@@ -370,9 +427,10 @@ var listRulesetsThunk = createAsyncThunk(
|
|
|
370
427
|
async ({ apiUrl, apiKey }, { dispatch: dispatch2, rejectWithValue }) => {
|
|
371
428
|
try {
|
|
372
429
|
const url = apiUrl || "https://api.forboc.ai";
|
|
430
|
+
requireApiKeyGuidance(url, apiKey);
|
|
373
431
|
return await dispatch2(sdkApi.endpoints.getRulesets.initiate({ apiUrl: url, apiKey })).unwrap();
|
|
374
|
-
} catch (
|
|
375
|
-
return rejectWithValue(
|
|
432
|
+
} catch (error) {
|
|
433
|
+
return rejectWithValue(extractThunkErrorMessage(error, "Failed to list rulesets"));
|
|
376
434
|
}
|
|
377
435
|
}
|
|
378
436
|
);
|
|
@@ -381,9 +439,10 @@ var listRulePresetsThunk = createAsyncThunk(
|
|
|
381
439
|
async ({ apiUrl, apiKey }, { dispatch: dispatch2, rejectWithValue }) => {
|
|
382
440
|
try {
|
|
383
441
|
const url = apiUrl || "https://api.forboc.ai";
|
|
442
|
+
requireApiKeyGuidance(url, apiKey);
|
|
384
443
|
return await dispatch2(sdkApi.endpoints.getRulePresets.initiate({ apiUrl: url, apiKey })).unwrap();
|
|
385
|
-
} catch (
|
|
386
|
-
return rejectWithValue(
|
|
444
|
+
} catch (error) {
|
|
445
|
+
return rejectWithValue(extractThunkErrorMessage(error, "Failed to list rule presets"));
|
|
387
446
|
}
|
|
388
447
|
}
|
|
389
448
|
);
|
|
@@ -392,9 +451,10 @@ var registerRulesetThunk = createAsyncThunk(
|
|
|
392
451
|
async ({ ruleset, apiUrl, apiKey }, { dispatch: dispatch2, rejectWithValue }) => {
|
|
393
452
|
try {
|
|
394
453
|
const url = apiUrl || "https://api.forboc.ai";
|
|
454
|
+
requireApiKeyGuidance(url, apiKey);
|
|
395
455
|
return await dispatch2(sdkApi.endpoints.postRuleRegister.initiate({ request: ruleset, apiUrl: url, apiKey })).unwrap();
|
|
396
|
-
} catch (
|
|
397
|
-
return rejectWithValue(
|
|
456
|
+
} catch (error) {
|
|
457
|
+
return rejectWithValue(extractThunkErrorMessage(error, "Failed to register ruleset"));
|
|
398
458
|
}
|
|
399
459
|
}
|
|
400
460
|
);
|
|
@@ -403,9 +463,10 @@ var deleteRulesetThunk = createAsyncThunk(
|
|
|
403
463
|
async ({ rulesetId, apiUrl, apiKey }, { dispatch: dispatch2, rejectWithValue }) => {
|
|
404
464
|
try {
|
|
405
465
|
const url = apiUrl || "https://api.forboc.ai";
|
|
466
|
+
requireApiKeyGuidance(url, apiKey);
|
|
406
467
|
return await dispatch2(sdkApi.endpoints.deleteRule.initiate({ rulesetId, apiUrl: url, apiKey })).unwrap();
|
|
407
|
-
} catch (
|
|
408
|
-
return rejectWithValue(
|
|
468
|
+
} catch (error) {
|
|
469
|
+
return rejectWithValue(extractThunkErrorMessage(error, "Failed to delete ruleset"));
|
|
409
470
|
}
|
|
410
471
|
}
|
|
411
472
|
);
|
|
@@ -454,6 +515,124 @@ var bridgeSlice_default = bridgeSlice.reducer;
|
|
|
454
515
|
|
|
455
516
|
// src/soulSlice.ts
|
|
456
517
|
import { createSlice as createSlice2, createAsyncThunk as createAsyncThunk2 } from "@reduxjs/toolkit";
|
|
518
|
+
|
|
519
|
+
// src/handlers/arweave.ts
|
|
520
|
+
var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
521
|
+
var getLocalWalletToken = () => {
|
|
522
|
+
const maybeEnv = globalThis.process?.env;
|
|
523
|
+
return maybeEnv?.ARWEAVE_WALLET_JWK ?? null;
|
|
524
|
+
};
|
|
525
|
+
var withTimeout = async (promiseFactory, timeoutMs = 6e4) => {
|
|
526
|
+
const controller = new AbortController();
|
|
527
|
+
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
528
|
+
try {
|
|
529
|
+
return await promiseFactory(controller.signal);
|
|
530
|
+
} finally {
|
|
531
|
+
clearTimeout(timeout);
|
|
532
|
+
}
|
|
533
|
+
};
|
|
534
|
+
async function handler_ArweaveUpload(instruction, maxRetries = 3) {
|
|
535
|
+
const headers = {
|
|
536
|
+
"Content-Type": instruction.auiContentType || "application/json"
|
|
537
|
+
};
|
|
538
|
+
const authToken = instruction.auiAuthHeader ?? (getLocalWalletToken() ? `Bearer ${getLocalWalletToken()}` : null);
|
|
539
|
+
if (authToken) {
|
|
540
|
+
headers.Authorization = authToken;
|
|
541
|
+
}
|
|
542
|
+
let attempt = 0;
|
|
543
|
+
while (attempt < maxRetries) {
|
|
544
|
+
attempt += 1;
|
|
545
|
+
try {
|
|
546
|
+
const response = await withTimeout(
|
|
547
|
+
(signal) => fetch(instruction.auiEndpoint, {
|
|
548
|
+
method: "POST",
|
|
549
|
+
headers,
|
|
550
|
+
body: JSON.stringify(instruction.auiPayload),
|
|
551
|
+
signal
|
|
552
|
+
})
|
|
553
|
+
);
|
|
554
|
+
let responseBody = null;
|
|
555
|
+
try {
|
|
556
|
+
responseBody = await response.json();
|
|
557
|
+
} catch {
|
|
558
|
+
responseBody = null;
|
|
559
|
+
}
|
|
560
|
+
const txId = responseBody?.id ?? `ar_tx_sdk_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
561
|
+
const success = response.status >= 200 && response.status < 300;
|
|
562
|
+
if (!success && attempt < maxRetries) {
|
|
563
|
+
await sleep(250 * 2 ** (attempt - 1));
|
|
564
|
+
continue;
|
|
565
|
+
}
|
|
566
|
+
return {
|
|
567
|
+
aurTxId: txId,
|
|
568
|
+
aurStatus: response.status,
|
|
569
|
+
aurSuccess: success,
|
|
570
|
+
aurError: success ? null : `upload_failed_status_${response.status}`
|
|
571
|
+
};
|
|
572
|
+
} catch (error) {
|
|
573
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
574
|
+
if (attempt < maxRetries) {
|
|
575
|
+
await sleep(250 * 2 ** (attempt - 1));
|
|
576
|
+
continue;
|
|
577
|
+
}
|
|
578
|
+
return {
|
|
579
|
+
aurTxId: `ar_tx_failed_${Date.now()}`,
|
|
580
|
+
aurStatus: 0,
|
|
581
|
+
aurSuccess: false,
|
|
582
|
+
aurError: `upload_request_failed:${message}`
|
|
583
|
+
};
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
return {
|
|
587
|
+
aurTxId: `ar_tx_failed_${Date.now()}`,
|
|
588
|
+
aurStatus: 0,
|
|
589
|
+
aurSuccess: false,
|
|
590
|
+
aurError: "upload_retry_exhausted"
|
|
591
|
+
};
|
|
592
|
+
}
|
|
593
|
+
async function handler_ArweaveDownload(instruction) {
|
|
594
|
+
try {
|
|
595
|
+
const response = await withTimeout(
|
|
596
|
+
(signal) => fetch(instruction.adiGatewayUrl, {
|
|
597
|
+
method: "GET",
|
|
598
|
+
signal
|
|
599
|
+
})
|
|
600
|
+
);
|
|
601
|
+
if (response.status < 200 || response.status >= 300) {
|
|
602
|
+
return {
|
|
603
|
+
adrBody: null,
|
|
604
|
+
adrStatus: response.status,
|
|
605
|
+
adrSuccess: false,
|
|
606
|
+
adrError: `download_failed_status_${response.status}`
|
|
607
|
+
};
|
|
608
|
+
}
|
|
609
|
+
try {
|
|
610
|
+
const body = await response.json();
|
|
611
|
+
return {
|
|
612
|
+
adrBody: body,
|
|
613
|
+
adrStatus: response.status,
|
|
614
|
+
adrSuccess: true,
|
|
615
|
+
adrError: null
|
|
616
|
+
};
|
|
617
|
+
} catch {
|
|
618
|
+
return {
|
|
619
|
+
adrBody: null,
|
|
620
|
+
adrStatus: response.status,
|
|
621
|
+
adrSuccess: false,
|
|
622
|
+
adrError: "download_invalid_json"
|
|
623
|
+
};
|
|
624
|
+
}
|
|
625
|
+
} catch (error) {
|
|
626
|
+
return {
|
|
627
|
+
adrBody: null,
|
|
628
|
+
adrStatus: 0,
|
|
629
|
+
adrSuccess: false,
|
|
630
|
+
adrError: error instanceof Error ? error.message : String(error)
|
|
631
|
+
};
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
// src/soulSlice.ts
|
|
457
636
|
var initialState2 = {
|
|
458
637
|
exportStatus: "idle",
|
|
459
638
|
importStatus: "idle",
|
|
@@ -464,26 +643,45 @@ var initialState2 = {
|
|
|
464
643
|
};
|
|
465
644
|
var remoteExportSoulThunk = createAsyncThunk2(
|
|
466
645
|
"soul/export",
|
|
467
|
-
async ({ npcId: argNpcId, apiUrl, apiKey
|
|
646
|
+
async ({ npcId: argNpcId, apiUrl, apiKey }, { getState, dispatch: dispatch2, rejectWithValue }) => {
|
|
468
647
|
try {
|
|
469
648
|
const state = getState().npc;
|
|
470
649
|
const npcId = argNpcId || state.activeNpcId;
|
|
471
650
|
const npc = state.entities[npcId];
|
|
472
651
|
if (!npc) throw new Error(`NPC ${npcId} not found`);
|
|
473
652
|
const url = apiUrl || "https://api.forboc.ai";
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
653
|
+
requireApiKeyGuidance(url, apiKey);
|
|
654
|
+
const phase1 = await dispatch2(
|
|
655
|
+
sdkApi.endpoints.postSoulExport.initiate({
|
|
656
|
+
npcId,
|
|
657
|
+
request: { npcIdRef: npcId, persona: npc.persona || "NPC", npcState: npc.state },
|
|
658
|
+
apiUrl: url,
|
|
659
|
+
apiKey
|
|
660
|
+
})
|
|
661
|
+
).unwrap();
|
|
662
|
+
const uploadResult = await handler_ArweaveUpload({
|
|
663
|
+
...phase1.se1Instruction,
|
|
664
|
+
auiAuthHeader: phase1.se1Instruction.auiAuthHeader ?? null
|
|
665
|
+
});
|
|
666
|
+
const final = await dispatch2(
|
|
667
|
+
sdkApi.endpoints.postSoulExportConfirm.initiate({
|
|
668
|
+
npcId,
|
|
669
|
+
request: {
|
|
670
|
+
secUploadResult: uploadResult,
|
|
671
|
+
secSignedPayload: phase1.se1SignedPayload,
|
|
672
|
+
secSignature: phase1.se1Signature
|
|
673
|
+
},
|
|
674
|
+
apiUrl: url,
|
|
675
|
+
apiKey
|
|
676
|
+
})
|
|
677
|
+
).unwrap();
|
|
480
678
|
return {
|
|
481
|
-
txId:
|
|
482
|
-
url:
|
|
483
|
-
soul:
|
|
679
|
+
txId: final.txId,
|
|
680
|
+
url: final.arweaveUrl,
|
|
681
|
+
soul: final.soul
|
|
484
682
|
};
|
|
485
|
-
} catch (
|
|
486
|
-
return rejectWithValue(
|
|
683
|
+
} catch (error) {
|
|
684
|
+
return rejectWithValue(extractThunkErrorMessage(error, "Soul export failed"));
|
|
487
685
|
}
|
|
488
686
|
}
|
|
489
687
|
);
|
|
@@ -492,10 +690,31 @@ var importSoulFromArweaveThunk = createAsyncThunk2(
|
|
|
492
690
|
async ({ txId, apiUrl, apiKey }, { dispatch: dispatch2, rejectWithValue }) => {
|
|
493
691
|
try {
|
|
494
692
|
const url = apiUrl || "https://api.forboc.ai";
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
693
|
+
requireApiKeyGuidance(url, apiKey);
|
|
694
|
+
const phase1 = await dispatch2(
|
|
695
|
+
sdkApi.endpoints.postNpcImport.initiate({ request: { txIdRef: txId }, apiUrl: url, apiKey })
|
|
696
|
+
).unwrap();
|
|
697
|
+
const downloadResult = await handler_ArweaveDownload(phase1.si1Instruction);
|
|
698
|
+
const npc = await dispatch2(
|
|
699
|
+
sdkApi.endpoints.postNpcImportConfirm.initiate({
|
|
700
|
+
request: {
|
|
701
|
+
sicTxId: txId,
|
|
702
|
+
sicDownloadResult: downloadResult
|
|
703
|
+
},
|
|
704
|
+
apiUrl: url,
|
|
705
|
+
apiKey
|
|
706
|
+
})
|
|
707
|
+
).unwrap();
|
|
708
|
+
return {
|
|
709
|
+
id: txId,
|
|
710
|
+
version: "2.0.0",
|
|
711
|
+
name: npc.npcId,
|
|
712
|
+
persona: npc.persona,
|
|
713
|
+
memories: [],
|
|
714
|
+
state: npc.data || {}
|
|
715
|
+
};
|
|
716
|
+
} catch (error) {
|
|
717
|
+
return rejectWithValue(extractThunkErrorMessage(error, "Soul import failed"));
|
|
499
718
|
}
|
|
500
719
|
}
|
|
501
720
|
);
|
|
@@ -504,10 +723,11 @@ var getSoulListThunk = createAsyncThunk2(
|
|
|
504
723
|
async ({ limit = 50, apiUrl, apiKey }, { dispatch: dispatch2, rejectWithValue }) => {
|
|
505
724
|
try {
|
|
506
725
|
const url = apiUrl || "https://api.forboc.ai";
|
|
726
|
+
requireApiKeyGuidance(url, apiKey);
|
|
507
727
|
const data = await dispatch2(sdkApi.endpoints.getSouls.initiate({ limit, apiUrl: url, apiKey })).unwrap();
|
|
508
728
|
return data.souls || [];
|
|
509
|
-
} catch (
|
|
510
|
-
return rejectWithValue(
|
|
729
|
+
} catch (error) {
|
|
730
|
+
return rejectWithValue(extractThunkErrorMessage(error, "Failed to list souls"));
|
|
511
731
|
}
|
|
512
732
|
}
|
|
513
733
|
);
|
|
@@ -516,9 +736,10 @@ var verifySoulThunk = createAsyncThunk2(
|
|
|
516
736
|
async ({ txId, apiUrl, apiKey }, { dispatch: dispatch2, rejectWithValue }) => {
|
|
517
737
|
try {
|
|
518
738
|
const url = apiUrl || "https://api.forboc.ai";
|
|
739
|
+
requireApiKeyGuidance(url, apiKey);
|
|
519
740
|
return await dispatch2(sdkApi.endpoints.postSoulVerify.initiate({ txId, apiUrl: url, apiKey })).unwrap();
|
|
520
|
-
} catch (
|
|
521
|
-
return rejectWithValue(
|
|
741
|
+
} catch (error) {
|
|
742
|
+
return rejectWithValue(extractThunkErrorMessage(error, "Soul verify failed"));
|
|
522
743
|
}
|
|
523
744
|
}
|
|
524
745
|
);
|
|
@@ -527,13 +748,24 @@ var importNpcFromSoulThunk = createAsyncThunk2(
|
|
|
527
748
|
async ({ txId, apiUrl, apiKey }, { dispatch: dispatch2, rejectWithValue }) => {
|
|
528
749
|
try {
|
|
529
750
|
const url = apiUrl || "https://api.forboc.ai";
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
751
|
+
requireApiKeyGuidance(url, apiKey);
|
|
752
|
+
const phase1 = await dispatch2(
|
|
753
|
+
sdkApi.endpoints.postNpcImport.initiate({
|
|
754
|
+
request: { txIdRef: txId },
|
|
755
|
+
apiUrl: url,
|
|
756
|
+
apiKey
|
|
757
|
+
})
|
|
758
|
+
).unwrap();
|
|
759
|
+
const downloadResult = await handler_ArweaveDownload(phase1.si1Instruction);
|
|
760
|
+
return await dispatch2(
|
|
761
|
+
sdkApi.endpoints.postNpcImportConfirm.initiate({
|
|
762
|
+
request: { sicTxId: txId, sicDownloadResult: downloadResult },
|
|
763
|
+
apiUrl: url,
|
|
764
|
+
apiKey
|
|
765
|
+
})
|
|
766
|
+
).unwrap();
|
|
767
|
+
} catch (error) {
|
|
768
|
+
return rejectWithValue(extractThunkErrorMessage(error, "NPC import from soul failed"));
|
|
537
769
|
}
|
|
538
770
|
}
|
|
539
771
|
);
|
|
@@ -592,6 +824,7 @@ var startGhostThunk = createAsyncThunk3(
|
|
|
592
824
|
async (config, { dispatch: dispatch2, rejectWithValue }) => {
|
|
593
825
|
try {
|
|
594
826
|
const apiUrl = config.apiUrl || "https://api.forboc.ai";
|
|
827
|
+
requireApiKeyGuidance(apiUrl, config.apiKey);
|
|
595
828
|
const data = await dispatch2(sdkApi.endpoints.postGhostRun.initiate({
|
|
596
829
|
request: { testSuite: config.testSuite, duration: config.duration ?? 300 },
|
|
597
830
|
apiUrl,
|
|
@@ -601,8 +834,8 @@ var startGhostThunk = createAsyncThunk3(
|
|
|
601
834
|
sessionId: data.sessionId,
|
|
602
835
|
status: data.runStatus
|
|
603
836
|
};
|
|
604
|
-
} catch (
|
|
605
|
-
return rejectWithValue(
|
|
837
|
+
} catch (error) {
|
|
838
|
+
return rejectWithValue(extractThunkErrorMessage(error, "Failed to start Ghost"));
|
|
606
839
|
}
|
|
607
840
|
}
|
|
608
841
|
);
|
|
@@ -614,6 +847,7 @@ var getGhostStatusThunk = createAsyncThunk3(
|
|
|
614
847
|
const targetSession = sessionId || state.activeSessionId;
|
|
615
848
|
if (!targetSession) throw new Error("No active Ghost session");
|
|
616
849
|
const url = apiUrl || "https://api.forboc.ai";
|
|
850
|
+
requireApiKeyGuidance(url, apiKey);
|
|
617
851
|
const data = await dispatch2(sdkApi.endpoints.getGhostStatus.initiate({ sessionId: targetSession, apiUrl: url, apiKey })).unwrap();
|
|
618
852
|
return {
|
|
619
853
|
sessionId: data.ghostSessionId,
|
|
@@ -623,8 +857,8 @@ var getGhostStatusThunk = createAsyncThunk3(
|
|
|
623
857
|
duration: data.ghostDuration || 0,
|
|
624
858
|
errors: data.ghostErrors
|
|
625
859
|
};
|
|
626
|
-
} catch (
|
|
627
|
-
return rejectWithValue(
|
|
860
|
+
} catch (error) {
|
|
861
|
+
return rejectWithValue(extractThunkErrorMessage(error, "Failed to get ghost status"));
|
|
628
862
|
}
|
|
629
863
|
}
|
|
630
864
|
);
|
|
@@ -636,6 +870,7 @@ var getGhostResultsThunk = createAsyncThunk3(
|
|
|
636
870
|
const targetSession = sessionId || state.activeSessionId;
|
|
637
871
|
if (!targetSession) throw new Error("No active Ghost session");
|
|
638
872
|
const url = apiUrl || "https://api.forboc.ai";
|
|
873
|
+
requireApiKeyGuidance(url, apiKey);
|
|
639
874
|
const data = await dispatch2(sdkApi.endpoints.getGhostResults.initiate({ sessionId: targetSession, apiUrl: url, apiKey })).unwrap();
|
|
640
875
|
return {
|
|
641
876
|
sessionId: data.resultsSessionId,
|
|
@@ -654,8 +889,8 @@ var getGhostResultsThunk = createAsyncThunk3(
|
|
|
654
889
|
coverage: data.resultsCoverage,
|
|
655
890
|
metrics: Object.fromEntries(data.resultsMetrics || [])
|
|
656
891
|
};
|
|
657
|
-
} catch (
|
|
658
|
-
return rejectWithValue(
|
|
892
|
+
} catch (error) {
|
|
893
|
+
return rejectWithValue(extractThunkErrorMessage(error, "Failed to get ghost results"));
|
|
659
894
|
}
|
|
660
895
|
}
|
|
661
896
|
);
|
|
@@ -667,14 +902,15 @@ var stopGhostThunk = createAsyncThunk3(
|
|
|
667
902
|
const targetSession = sessionId || state.activeSessionId;
|
|
668
903
|
if (!targetSession) throw new Error("No active Ghost session");
|
|
669
904
|
const url = apiUrl || "https://api.forboc.ai";
|
|
905
|
+
requireApiKeyGuidance(url, apiKey);
|
|
670
906
|
const data = await dispatch2(sdkApi.endpoints.postGhostStop.initiate({ sessionId: targetSession, apiUrl: url, apiKey })).unwrap();
|
|
671
907
|
return {
|
|
672
908
|
stopped: data.stopped,
|
|
673
909
|
status: data.stopStatus,
|
|
674
910
|
sessionId: data.stopSessionId
|
|
675
911
|
};
|
|
676
|
-
} catch (
|
|
677
|
-
return rejectWithValue(
|
|
912
|
+
} catch (error) {
|
|
913
|
+
return rejectWithValue(extractThunkErrorMessage(error, "Failed to stop ghost session"));
|
|
678
914
|
}
|
|
679
915
|
}
|
|
680
916
|
);
|
|
@@ -683,6 +919,7 @@ var getGhostHistoryThunk = createAsyncThunk3(
|
|
|
683
919
|
async ({ limit = 10, apiUrl, apiKey }, { dispatch: dispatch2, rejectWithValue }) => {
|
|
684
920
|
try {
|
|
685
921
|
const url = apiUrl || "https://api.forboc.ai";
|
|
922
|
+
requireApiKeyGuidance(url, apiKey);
|
|
686
923
|
const data = await dispatch2(sdkApi.endpoints.getGhostHistory.initiate({ limit, apiUrl: url, apiKey })).unwrap();
|
|
687
924
|
return (data.sessions || []).map((s) => ({
|
|
688
925
|
sessionId: s.sessionId,
|
|
@@ -692,8 +929,8 @@ var getGhostHistoryThunk = createAsyncThunk3(
|
|
|
692
929
|
status: s.status,
|
|
693
930
|
passRate: s.passRate
|
|
694
931
|
}));
|
|
695
|
-
} catch (
|
|
696
|
-
return rejectWithValue(
|
|
932
|
+
} catch (error) {
|
|
933
|
+
return rejectWithValue(extractThunkErrorMessage(error, "Failed to get ghost history"));
|
|
697
934
|
}
|
|
698
935
|
}
|
|
699
936
|
);
|
|
@@ -728,7 +965,7 @@ var ghostSlice = createSlice3({
|
|
|
728
965
|
state.status = "completed";
|
|
729
966
|
}).addCase(stopGhostThunk.fulfilled, (state, action) => {
|
|
730
967
|
if (action.payload.stopped) {
|
|
731
|
-
state.status = "
|
|
968
|
+
state.status = "completed";
|
|
732
969
|
} else {
|
|
733
970
|
state.error = action.payload.status || "Ghost stop request did not stop a session";
|
|
734
971
|
}
|
|
@@ -743,7 +980,7 @@ var { clearGhostSession } = ghostSlice.actions;
|
|
|
743
980
|
var ghostSlice_default = ghostSlice.reducer;
|
|
744
981
|
|
|
745
982
|
// src/utils/sdkVersion.ts
|
|
746
|
-
var SDK_VERSION = "0.6.
|
|
983
|
+
var SDK_VERSION = "0.6.1";
|
|
747
984
|
|
|
748
985
|
// src/utils/generateNPCId.ts
|
|
749
986
|
var generateNPCId = () => `ag_${Date.now().toString(36)}`;
|
|
@@ -824,7 +1061,8 @@ var npcSlice = createSlice4({
|
|
|
824
1061
|
persona,
|
|
825
1062
|
state: initialState5 || {},
|
|
826
1063
|
history: [],
|
|
827
|
-
isBlocked: false
|
|
1064
|
+
isBlocked: false,
|
|
1065
|
+
stateLog: [{ timestamp: Date.now(), delta: initialState5 || {}, state: initialState5 || {} }]
|
|
828
1066
|
});
|
|
829
1067
|
state.activeNpcId = id;
|
|
830
1068
|
},
|
|
@@ -839,7 +1077,9 @@ var npcSlice = createSlice4({
|
|
|
839
1077
|
const { id, delta } = action.payload;
|
|
840
1078
|
const npc = state.entities[id];
|
|
841
1079
|
if (npc) {
|
|
842
|
-
|
|
1080
|
+
const newState = { ...npc.state, ...delta };
|
|
1081
|
+
npc.state = newState;
|
|
1082
|
+
npc.stateLog.push({ timestamp: Date.now(), delta, state: newState });
|
|
843
1083
|
}
|
|
844
1084
|
},
|
|
845
1085
|
addToHistory: (state, action) => {
|
|
@@ -909,6 +1149,7 @@ var initRemoteCortexThunk = createAsyncThunk4(
|
|
|
909
1149
|
async ({ model = "api-integrated", authKey, apiUrl, apiKey }, { dispatch: dispatch2, rejectWithValue }) => {
|
|
910
1150
|
try {
|
|
911
1151
|
const url = apiUrl || "https://api.forboc.ai";
|
|
1152
|
+
requireApiKeyGuidance(url, apiKey);
|
|
912
1153
|
const data = await dispatch2(sdkApi.endpoints.postCortexInit.initiate({
|
|
913
1154
|
request: { requestedModel: model, authKey },
|
|
914
1155
|
apiUrl: url,
|
|
@@ -920,8 +1161,8 @@ var initRemoteCortexThunk = createAsyncThunk4(
|
|
|
920
1161
|
ready: data.state?.toLowerCase() === "ready",
|
|
921
1162
|
engine: "remote"
|
|
922
1163
|
};
|
|
923
|
-
} catch (
|
|
924
|
-
return rejectWithValue(
|
|
1164
|
+
} catch (error) {
|
|
1165
|
+
return rejectWithValue(extractThunkErrorMessage(error, "Remote cortex init failed"));
|
|
925
1166
|
}
|
|
926
1167
|
}
|
|
927
1168
|
);
|
|
@@ -930,9 +1171,10 @@ var listCortexModelsThunk = createAsyncThunk4(
|
|
|
930
1171
|
async ({ apiUrl, apiKey }, { dispatch: dispatch2, rejectWithValue }) => {
|
|
931
1172
|
try {
|
|
932
1173
|
const url = apiUrl || "https://api.forboc.ai";
|
|
1174
|
+
requireApiKeyGuidance(url, apiKey);
|
|
933
1175
|
return await dispatch2(sdkApi.endpoints.getCortexModels.initiate({ apiUrl: url, apiKey })).unwrap();
|
|
934
|
-
} catch (
|
|
935
|
-
return rejectWithValue(
|
|
1176
|
+
} catch (error) {
|
|
1177
|
+
return rejectWithValue(extractThunkErrorMessage(error, "Failed to list cortex models"));
|
|
936
1178
|
}
|
|
937
1179
|
}
|
|
938
1180
|
);
|
|
@@ -940,6 +1182,7 @@ var completeRemoteThunk = createAsyncThunk4(
|
|
|
940
1182
|
"cortex/completeRemote",
|
|
941
1183
|
async ({ cortexId, prompt, options, apiUrl, apiKey }, { dispatch: dispatch2, rejectWithValue }) => {
|
|
942
1184
|
try {
|
|
1185
|
+
requireApiKeyGuidance(apiUrl, apiKey);
|
|
943
1186
|
const data = await dispatch2(sdkApi.endpoints.postCortexComplete.initiate({
|
|
944
1187
|
cortexId,
|
|
945
1188
|
prompt,
|
|
@@ -948,8 +1191,8 @@ var completeRemoteThunk = createAsyncThunk4(
|
|
|
948
1191
|
apiKey
|
|
949
1192
|
})).unwrap();
|
|
950
1193
|
return data.text;
|
|
951
|
-
} catch (
|
|
952
|
-
return rejectWithValue(
|
|
1194
|
+
} catch (error) {
|
|
1195
|
+
return rejectWithValue(extractThunkErrorMessage(error, "Remote completing failed"));
|
|
953
1196
|
}
|
|
954
1197
|
}
|
|
955
1198
|
);
|
|
@@ -1184,6 +1427,13 @@ var dispatch = store.dispatch;
|
|
|
1184
1427
|
|
|
1185
1428
|
// src/thunks.ts
|
|
1186
1429
|
import { createAsyncThunk as createAsyncThunk5 } from "@reduxjs/toolkit";
|
|
1430
|
+
var extractThunkErrorMessage2 = (e) => {
|
|
1431
|
+
if (typeof e === "string") return e;
|
|
1432
|
+
if (e?.data?.message) return String(e.data.message);
|
|
1433
|
+
if (e?.error) return String(e.error);
|
|
1434
|
+
if (e?.message) return String(e.message);
|
|
1435
|
+
return "Protocol processing failed";
|
|
1436
|
+
};
|
|
1187
1437
|
var processNPC = createAsyncThunk5(
|
|
1188
1438
|
"npc/process",
|
|
1189
1439
|
async ({ npcId: argNpcId, text, context = {}, apiUrl, apiKey, memory, cortex, persona: argPersona }, { getState, dispatch: dispatch2, rejectWithValue }) => {
|
|
@@ -1207,61 +1457,111 @@ var processNPC = createAsyncThunk5(
|
|
|
1207
1457
|
const directiveId = `${npcId}:${Date.now()}`;
|
|
1208
1458
|
dispatch2(directiveRunStarted({ id: directiveId, npcId, observation: text }));
|
|
1209
1459
|
try {
|
|
1210
|
-
const
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
const contextResult = await dispatch2(
|
|
1223
|
-
sdkApi.endpoints.postContext.initiate({ npcId, request: { memories: recalledMemories, observation: text, npcState: currentState, persona }, apiUrl, apiKey })
|
|
1224
|
-
).unwrap();
|
|
1225
|
-
dispatch2(contextComposed({ id: directiveId, prompt: contextResult.prompt, constraints: contextResult.constraints }));
|
|
1226
|
-
const generatedText = await cortex.complete(contextResult.prompt, {
|
|
1227
|
-
maxTokens: contextResult.constraints.maxTokens,
|
|
1228
|
-
temperature: contextResult.constraints.temperature,
|
|
1229
|
-
stop: contextResult.constraints.stop
|
|
1230
|
-
});
|
|
1231
|
-
const verdictResult = await dispatch2(
|
|
1232
|
-
sdkApi.endpoints.postVerdict.initiate({ npcId, request: { generatedOutput: generatedText, observation: text, npcState: currentState }, apiUrl, apiKey })
|
|
1233
|
-
).unwrap();
|
|
1234
|
-
dispatch2(verdictValidated({ id: directiveId, verdict: verdictResult }));
|
|
1235
|
-
if (!verdictResult.valid) {
|
|
1236
|
-
dispatch2(blockAction({ id: npcId, reason: verdictResult.dialogue || "Validation Failed" }));
|
|
1237
|
-
return {
|
|
1238
|
-
dialogue: verdictResult.dialogue,
|
|
1239
|
-
action: verdictResult.action,
|
|
1240
|
-
thought: verdictResult.dialogue
|
|
1241
|
-
};
|
|
1242
|
-
}
|
|
1243
|
-
if (verdictResult.memoryStore?.length && !memory) {
|
|
1244
|
-
return rejectWithValue("API returned memoryStore instructions, but no memory engine is configured");
|
|
1245
|
-
}
|
|
1246
|
-
if (memory && verdictResult.memoryStore) {
|
|
1247
|
-
for (const inst of verdictResult.memoryStore) {
|
|
1248
|
-
await memory.store(inst.text, inst.type, inst.importance);
|
|
1460
|
+
const initialTape = {
|
|
1461
|
+
observation: text,
|
|
1462
|
+
context,
|
|
1463
|
+
npcState: currentState,
|
|
1464
|
+
persona,
|
|
1465
|
+
memories: [],
|
|
1466
|
+
vectorQueried: false
|
|
1467
|
+
};
|
|
1468
|
+
const maxTurns = 12;
|
|
1469
|
+
const persistMemoryInstructionsRecursively = async (instructions, index = 0) => {
|
|
1470
|
+
if (!memory || index >= instructions.length) {
|
|
1471
|
+
return;
|
|
1249
1472
|
}
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
}
|
|
1254
|
-
const
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1473
|
+
const inst = instructions[index];
|
|
1474
|
+
await memory.store(inst.text, inst.type, inst.importance);
|
|
1475
|
+
await persistMemoryInstructionsRecursively(instructions, index + 1);
|
|
1476
|
+
};
|
|
1477
|
+
const runProtocolRecursively = async (tape, lastResult, turn) => {
|
|
1478
|
+
if (turn >= maxTurns) {
|
|
1479
|
+
return rejectWithValue(`Protocol loop exceeded max turns (${maxTurns})`);
|
|
1480
|
+
}
|
|
1481
|
+
const request = { tape, lastResult };
|
|
1482
|
+
const processResult = await dispatch2(
|
|
1483
|
+
sdkApi.endpoints.postNpcProcess.initiate({ npcId, request, apiUrl, apiKey })
|
|
1484
|
+
).unwrap();
|
|
1485
|
+
const nextTape = processResult.tape;
|
|
1486
|
+
const instruction = processResult.instruction;
|
|
1487
|
+
if (instruction.type === "IdentifyActor") {
|
|
1488
|
+
return runProtocolRecursively(nextTape, {
|
|
1489
|
+
type: "IdentifyActorResult",
|
|
1490
|
+
actor: {
|
|
1491
|
+
npcId,
|
|
1492
|
+
persona,
|
|
1493
|
+
data: nextTape.npcState
|
|
1494
|
+
}
|
|
1495
|
+
}, turn + 1);
|
|
1496
|
+
}
|
|
1497
|
+
if (instruction.type === "QueryVector") {
|
|
1498
|
+
dispatch2(directiveReceived({
|
|
1499
|
+
id: directiveId,
|
|
1500
|
+
response: { memoryRecall: { query: instruction.query, limit: instruction.limit, threshold: instruction.threshold } }
|
|
1501
|
+
}));
|
|
1502
|
+
if (!memory) {
|
|
1503
|
+
return rejectWithValue("API requested memory recall, but no memory engine is configured");
|
|
1504
|
+
}
|
|
1505
|
+
const recalled = await memory.recall(instruction.query, instruction.limit, instruction.threshold);
|
|
1506
|
+
return runProtocolRecursively(nextTape, {
|
|
1507
|
+
type: "QueryVectorResult",
|
|
1508
|
+
memories: recalled.map((m) => ({ text: m.text, type: m.type, importance: m.importance, similarity: m.similarity }))
|
|
1509
|
+
}, turn + 1);
|
|
1510
|
+
}
|
|
1511
|
+
if (instruction.type === "ExecuteInference") {
|
|
1512
|
+
dispatch2(contextComposed({ id: directiveId, prompt: instruction.prompt, constraints: instruction.constraints }));
|
|
1513
|
+
const generatedText = await cortex.complete(instruction.prompt, {
|
|
1514
|
+
maxTokens: instruction.constraints.maxTokens,
|
|
1515
|
+
temperature: instruction.constraints.temperature,
|
|
1516
|
+
stop: instruction.constraints.stop
|
|
1517
|
+
});
|
|
1518
|
+
return runProtocolRecursively(nextTape, {
|
|
1519
|
+
type: "ExecuteInferenceResult",
|
|
1520
|
+
generatedOutput: generatedText
|
|
1521
|
+
}, turn + 1);
|
|
1522
|
+
}
|
|
1523
|
+
if (instruction.type === "Finalize") {
|
|
1524
|
+
const finalize = instruction;
|
|
1525
|
+
dispatch2(verdictValidated({
|
|
1526
|
+
id: directiveId,
|
|
1527
|
+
verdict: {
|
|
1528
|
+
valid: finalize.valid,
|
|
1529
|
+
signature: finalize.signature,
|
|
1530
|
+
memoryStore: finalize.memoryStore,
|
|
1531
|
+
stateDelta: finalize.stateTransform,
|
|
1532
|
+
action: finalize.action,
|
|
1533
|
+
dialogue: finalize.dialogue
|
|
1534
|
+
}
|
|
1535
|
+
}));
|
|
1536
|
+
if (!finalize.valid) {
|
|
1537
|
+
dispatch2(blockAction({ id: npcId, reason: finalize.dialogue || "Validation Failed" }));
|
|
1538
|
+
return {
|
|
1539
|
+
dialogue: finalize.dialogue,
|
|
1540
|
+
action: finalize.action,
|
|
1541
|
+
thought: finalize.dialogue
|
|
1542
|
+
};
|
|
1543
|
+
}
|
|
1544
|
+
if (finalize.memoryStore?.length && !memory) {
|
|
1545
|
+
return rejectWithValue("API returned memoryStore instructions, but no memory engine is configured");
|
|
1546
|
+
}
|
|
1547
|
+
await persistMemoryInstructionsRecursively(finalize.memoryStore || []);
|
|
1548
|
+
if (finalize.stateTransform) {
|
|
1549
|
+
dispatch2(updateNPCState({ id: npcId, delta: finalize.stateTransform }));
|
|
1550
|
+
}
|
|
1551
|
+
dispatch2(setLastAction({ id: npcId, action: finalize.action }));
|
|
1552
|
+
dispatch2(addToHistory({ id: npcId, role: "user", content: text }));
|
|
1553
|
+
dispatch2(addToHistory({ id: npcId, role: "assistant", content: finalize.dialogue }));
|
|
1554
|
+
return {
|
|
1555
|
+
dialogue: finalize.dialogue,
|
|
1556
|
+
action: finalize.action,
|
|
1557
|
+
thought: finalize.dialogue
|
|
1558
|
+
};
|
|
1559
|
+
}
|
|
1560
|
+
return rejectWithValue("API returned unknown instruction type");
|
|
1262
1561
|
};
|
|
1562
|
+
return runProtocolRecursively(initialTape, void 0, 0);
|
|
1263
1563
|
} catch (e) {
|
|
1264
|
-
const message = e
|
|
1564
|
+
const message = extractThunkErrorMessage2(e);
|
|
1265
1565
|
dispatch2(directiveRunFailed({ id: directiveId, error: String(message) }));
|
|
1266
1566
|
return rejectWithValue(String(message));
|
|
1267
1567
|
}
|
|
@@ -1381,6 +1681,8 @@ export {
|
|
|
1381
1681
|
getGhostStatusThunk,
|
|
1382
1682
|
getSoulListThunk,
|
|
1383
1683
|
ghostSlice,
|
|
1684
|
+
handler_ArweaveDownload,
|
|
1685
|
+
handler_ArweaveUpload,
|
|
1384
1686
|
importNpcFromSoulThunk,
|
|
1385
1687
|
importSoulFromArweaveThunk,
|
|
1386
1688
|
initRemoteCortexThunk,
|