@nookplot/cli 0.6.79 → 0.6.81
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/commands/gpu.d.ts +11 -6
- package/dist/commands/gpu.js +479 -6
- package/dist/commands/gpu.js.map +1 -1
- package/dist/commands/listen.js +152 -1615
- package/dist/commands/listen.js.map +1 -1
- package/dist/utils/agentLoop.js +43 -1503
- package/dist/utils/agentLoop.js.map +1 -1
- package/package.json +2 -2
package/dist/utils/agentLoop.js
CHANGED
|
@@ -11,7 +11,7 @@ import { existsSync, appendFileSync, statSync, mkdirSync } from "node:fs";
|
|
|
11
11
|
import { join } from "node:path";
|
|
12
12
|
import { homedir } from "node:os";
|
|
13
13
|
import { spawn } from "node:child_process";
|
|
14
|
-
import { NookplotRuntime, AutonomousAgent,
|
|
14
|
+
import { NookplotRuntime, AutonomousAgent, formatActionsForPrompt } from "@nookplot/runtime";
|
|
15
15
|
import { filterByProfile } from "../skillGenerator.js";
|
|
16
16
|
// ── Constants ─────────────────────────────────────────────────
|
|
17
17
|
const NOOKPLOT_DIR = join(homedir(), ".nookplot");
|
|
@@ -469,6 +469,7 @@ function _getAvailableActionsRaw(signalType) {
|
|
|
469
469
|
"list_project_files", "read_project_file", "list_commits", "get_commit_detail",
|
|
470
470
|
"gpu_search", "gpu_heartbeat", "gpu_challenge", "gpu_submit_challenge",
|
|
471
471
|
"gpu_submit_attestation", "gpu_update_attestation", "gpu_revoke_attestation",
|
|
472
|
+
"gpu_rent",
|
|
472
473
|
"ignore",
|
|
473
474
|
];
|
|
474
475
|
case "collab_request":
|
|
@@ -607,1513 +608,52 @@ function _getAvailableActionsRaw(signalType) {
|
|
|
607
608
|
}
|
|
608
609
|
}
|
|
609
610
|
// ── Execute agent action ──────────────────────────────────────
|
|
610
|
-
/** Validate an ID before URL interpolation — must be numeric or UUID. */
|
|
611
|
-
function validateId(id, name) {
|
|
612
|
-
const s = String(id ?? "");
|
|
613
|
-
if (/^\d+$/.test(s) || /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(s))
|
|
614
|
-
return s;
|
|
615
|
-
throw new Error(`Invalid ${name}: ${s}`);
|
|
616
|
-
}
|
|
617
611
|
export async function executeAgentAction(runtime, action, signal, log) {
|
|
618
612
|
const target = action.to || signal.senderAddress || "";
|
|
619
613
|
const content = action.content || "";
|
|
620
614
|
const channelId = action.channelId || signal.channelId || "";
|
|
621
615
|
try {
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
case "
|
|
643
|
-
|
|
644
|
-
if (
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
if (
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
case "unblock_agent":
|
|
664
|
-
if (target) {
|
|
665
|
-
await runtime.social.unblock(target);
|
|
666
|
-
}
|
|
667
|
-
break;
|
|
668
|
-
case "vote":
|
|
669
|
-
if (action.cid) {
|
|
670
|
-
await runtime.memory.vote({ cid: action.cid, type: (action.voteType || "up") });
|
|
671
|
-
}
|
|
672
|
-
break;
|
|
673
|
-
case "review":
|
|
674
|
-
case "review_commit":
|
|
675
|
-
case "comment": {
|
|
676
|
-
const projectId = (action.projectId || signal.projectId);
|
|
677
|
-
const commitId = (action.commitId || signal.commitId);
|
|
678
|
-
const verdict = action.action === "comment" ? "comment" : action.verdict || "comment";
|
|
679
|
-
const body = content || "Reviewed";
|
|
680
|
-
if (projectId && commitId) {
|
|
681
|
-
await runtime.projects.submitReview(projectId, commitId, verdict, body);
|
|
682
|
-
}
|
|
683
|
-
break;
|
|
684
|
-
}
|
|
685
|
-
case "request_ai_review": {
|
|
686
|
-
const projId2 = (action.projectId || signal.projectId);
|
|
687
|
-
const commitId2 = (action.commitId || signal.commitId);
|
|
688
|
-
if (projId2 && commitId2) {
|
|
689
|
-
const aiResult = await runtime.projects.requestAIReview(projId2, commitId2);
|
|
690
|
-
log(`AI review: ${aiResult.verdict} — ${aiResult.findingsCount} finding(s), cost ${aiResult.creditsCost} credits`);
|
|
691
|
-
}
|
|
692
|
-
break;
|
|
693
|
-
}
|
|
694
|
-
case "send_message":
|
|
695
|
-
if (target) {
|
|
696
|
-
await runtime.inbox.send({ to: target, content: content || "Hey! Looking forward to collaborating." });
|
|
697
|
-
}
|
|
698
|
-
else if (channelId) {
|
|
699
|
-
await runtime.channels.send(channelId, content || "Hey everyone! Excited to join.");
|
|
700
|
-
}
|
|
701
|
-
break;
|
|
702
|
-
case "grant": {
|
|
703
|
-
const projId = (action.projectId || signal.projectId);
|
|
704
|
-
const bId = (action.bountyId || signal.bountyId);
|
|
705
|
-
const reqAddr = (signal.senderAddress || target);
|
|
706
|
-
if (projId && bId) {
|
|
707
|
-
await runtime.connection.request("POST", `/v1/projects/${projId}/bounties/${bId}/grant-access`, { requesterAddress: reqAddr });
|
|
708
|
-
log(`[reactive] Granted bounty access for ${reqAddr?.slice(0, 10)}... on ${projId}`);
|
|
709
|
-
}
|
|
710
|
-
break;
|
|
711
|
-
}
|
|
712
|
-
case "deny": {
|
|
713
|
-
const projId = (action.projectId || signal.projectId);
|
|
714
|
-
const bId = (action.bountyId || signal.bountyId);
|
|
715
|
-
const reqAddr = (signal.senderAddress || target);
|
|
716
|
-
if (projId && bId) {
|
|
717
|
-
await runtime.connection.request("POST", `/v1/projects/${projId}/bounties/${bId}/deny-access`, { requesterAddress: reqAddr });
|
|
718
|
-
log(`[reactive] Denied bounty access for ${reqAddr?.slice(0, 10)}... on ${projId}`);
|
|
719
|
-
}
|
|
720
|
-
break;
|
|
721
|
-
}
|
|
722
|
-
case "claim":
|
|
723
|
-
case "claim_bounty": {
|
|
724
|
-
const rawBountyId = action.bountyId || signal.bountyId;
|
|
725
|
-
if (rawBountyId) {
|
|
726
|
-
const bountyId = validateId(rawBountyId, "bountyId");
|
|
727
|
-
const relay = await prepareSignRelay(runtime.connection, `/v1/prepare/bounty/${bountyId}/claim`, {});
|
|
728
|
-
log(`[reactive] Bounty claimed: ${bountyId} (tx: ${relay.txHash})`);
|
|
729
|
-
}
|
|
730
|
-
else {
|
|
731
|
-
log(`[reactive] Bounty claim requested but no bountyId provided`);
|
|
732
|
-
}
|
|
733
|
-
break;
|
|
734
|
-
}
|
|
735
|
-
case "approve_bounty_claimer": {
|
|
736
|
-
const rawBountyId = action.bountyId || signal.bountyId;
|
|
737
|
-
const claimer = action.claimer;
|
|
738
|
-
if (rawBountyId && claimer) {
|
|
739
|
-
const bountyId = validateId(rawBountyId, "bountyId");
|
|
740
|
-
const relay = await prepareSignRelay(runtime.connection, `/v1/prepare/bounty/${bountyId}/approve-claimer`, { claimer });
|
|
741
|
-
log(`[reactive] Bounty claimer approved: ${bountyId} → ${claimer} (tx: ${relay.txHash})`);
|
|
742
|
-
}
|
|
743
|
-
else {
|
|
744
|
-
log(`[reactive] approve_bounty_claimer requires bountyId and claimer`);
|
|
745
|
-
}
|
|
746
|
-
break;
|
|
747
|
-
}
|
|
748
|
-
case "apply_bounty": {
|
|
749
|
-
const bountyId = validateId(action.bountyId || signal.bountyId, "bountyId");
|
|
750
|
-
const applyMsg = content || action.message || "";
|
|
751
|
-
if (!applyMsg || applyMsg.length < 50)
|
|
752
|
-
throw new Error("apply_bounty requires a work submission (minimum 50 characters)");
|
|
753
|
-
await runtime.connection.request("POST", `/v1/bounties/${bountyId}/apply`, { message: applyMsg });
|
|
754
|
-
log(`[reactive] Applied to bounty: ${bountyId}`);
|
|
755
|
-
break;
|
|
756
|
-
}
|
|
757
|
-
case "submit_bounty_work": {
|
|
758
|
-
const bountyId = validateId(action.bountyId || signal.bountyId, "bountyId");
|
|
759
|
-
if (content) {
|
|
760
|
-
const cids = (action.deliverableCids ?? []);
|
|
761
|
-
await runtime.connection.request("POST", `/v1/bounties/${bountyId}/submissions`, { content, deliverableCids: cids });
|
|
762
|
-
log(`[reactive] Submitted work for bounty: ${bountyId}`);
|
|
763
|
-
}
|
|
764
|
-
break;
|
|
765
|
-
}
|
|
766
|
-
case "approve_bounty_application": {
|
|
767
|
-
const bountyId = validateId(action.bountyId || signal.bountyId, "bountyId");
|
|
768
|
-
const applicationId = validateId(action.applicationId, "applicationId");
|
|
769
|
-
await runtime.connection.request("POST", `/v1/bounties/${bountyId}/applications/${applicationId}/approve`, {});
|
|
770
|
-
log(`[reactive] Approved bounty application: ${applicationId} on bounty ${bountyId}`);
|
|
771
|
-
break;
|
|
772
|
-
}
|
|
773
|
-
case "reject_bounty_application": {
|
|
774
|
-
const bountyId = validateId(action.bountyId || signal.bountyId, "bountyId");
|
|
775
|
-
const applicationId = validateId(action.applicationId, "applicationId");
|
|
776
|
-
await runtime.connection.request("POST", `/v1/bounties/${bountyId}/applications/${applicationId}/reject`, {});
|
|
777
|
-
log(`[reactive] Rejected bounty application: ${applicationId} on bounty ${bountyId}`);
|
|
778
|
-
break;
|
|
779
|
-
}
|
|
780
|
-
case "select_bounty_submission": {
|
|
781
|
-
const bountyId = validateId(action.bountyId || signal.bountyId, "bountyId");
|
|
782
|
-
const submissionId = validateId(action.submissionId, "submissionId");
|
|
783
|
-
const selectResult = await runtime.connection.request("POST", `/v1/bounties/${bountyId}/submissions/${submissionId}/select`, {});
|
|
784
|
-
log(`[reactive] Selected bounty submission: ${submissionId} on bounty ${bountyId}`);
|
|
785
|
-
// Bridge: approve winner on-chain so they can claim
|
|
786
|
-
try {
|
|
787
|
-
const winnerAddress = selectResult?.winner?.applicantAddress;
|
|
788
|
-
if (winnerAddress) {
|
|
789
|
-
const relay = await prepareSignRelay(runtime.connection, `/v1/prepare/bounty/${bountyId}/approve-claimer`, { claimer: winnerAddress });
|
|
790
|
-
log(`[reactive] Approved claimer on-chain: ${bountyId} → ${winnerAddress} (tx: ${relay.txHash})`);
|
|
791
|
-
}
|
|
792
|
-
}
|
|
793
|
-
catch { /* non-fatal */ }
|
|
794
|
-
break;
|
|
795
|
-
}
|
|
796
|
-
case "create_community": {
|
|
797
|
-
const slug = action.slug;
|
|
798
|
-
const name = action.name || content;
|
|
799
|
-
const desc = action.description || content || "";
|
|
800
|
-
if (slug && name) {
|
|
801
|
-
const relay = await prepareSignRelay(runtime.connection, "/v1/prepare/community", { slug, name, description: desc });
|
|
802
|
-
log(`[reactive] Community created: ${slug} (tx: ${relay.txHash})`);
|
|
803
|
-
}
|
|
804
|
-
break;
|
|
805
|
-
}
|
|
806
|
-
case "create_project": {
|
|
807
|
-
const projName = action.name || content;
|
|
808
|
-
const projDesc = action.description || "";
|
|
809
|
-
const projId = action.projectId || projName?.toLowerCase().replace(/\s+/g, "-");
|
|
810
|
-
if (projId && projName) {
|
|
811
|
-
const discovery = await runtime.connection.request("POST", "/v1/projects/discover", { name: projName, description: projDesc });
|
|
812
|
-
const relay = await prepareSignRelay(runtime.connection, "/v1/prepare/project", {
|
|
813
|
-
discoveryId: discovery.discoveryId,
|
|
814
|
-
projectId: projId, name: projName, description: projDesc,
|
|
815
|
-
});
|
|
816
|
-
log(`[reactive] Project created: ${projId} (tx: ${relay.txHash})`);
|
|
817
|
-
}
|
|
818
|
-
break;
|
|
819
|
-
}
|
|
820
|
-
case "commit_files":
|
|
821
|
-
case "gateway_commit": {
|
|
822
|
-
const projId = (action.projectId || signal.projectId);
|
|
823
|
-
const files = action.files;
|
|
824
|
-
const msg = content || "Automated commit";
|
|
825
|
-
if (projId && files?.length) {
|
|
826
|
-
await runtime.projects.commitFiles(projId, files, msg);
|
|
827
|
-
}
|
|
828
|
-
break;
|
|
829
|
-
}
|
|
830
|
-
case "list_project_files": {
|
|
831
|
-
const projId = (action.projectId || signal.projectId);
|
|
832
|
-
if (projId) {
|
|
833
|
-
const files = await runtime.projects.listFiles(projId);
|
|
834
|
-
log(`[reactive] Listed ${files.length} files in project ${projId}`);
|
|
835
|
-
}
|
|
836
|
-
break;
|
|
837
|
-
}
|
|
838
|
-
case "read_project_file": {
|
|
839
|
-
const projId = (action.projectId || signal.projectId);
|
|
840
|
-
const filePath = action.filePath;
|
|
841
|
-
if (projId && filePath) {
|
|
842
|
-
const fileContent = await runtime.projects.readFile(projId, filePath);
|
|
843
|
-
log(`[reactive] Read file ${filePath} from project ${projId}`);
|
|
844
|
-
}
|
|
845
|
-
break;
|
|
846
|
-
}
|
|
847
|
-
case "list_commits": {
|
|
848
|
-
const projId = (action.projectId || signal.projectId);
|
|
849
|
-
if (projId) {
|
|
850
|
-
const limit = action.limit ?? 20;
|
|
851
|
-
const offset = action.offset ?? 0;
|
|
852
|
-
const commits = await runtime.projects.listCommits(projId, limit, offset);
|
|
853
|
-
log(`[reactive] Listed ${commits.length} commits in project ${projId}`);
|
|
854
|
-
}
|
|
855
|
-
break;
|
|
856
|
-
}
|
|
857
|
-
case "get_commit_detail": {
|
|
858
|
-
const projId = (action.projectId || signal.projectId);
|
|
859
|
-
const commitId = action.commitId;
|
|
860
|
-
if (projId && commitId) {
|
|
861
|
-
const commit = await runtime.projects.getCommit(projId, commitId);
|
|
862
|
-
log(`[reactive] Got commit detail ${commitId} from project ${projId}`);
|
|
863
|
-
}
|
|
864
|
-
break;
|
|
865
|
-
}
|
|
866
|
-
case "add_collaborator": {
|
|
867
|
-
const projId = (action.projectId || signal.projectId);
|
|
868
|
-
const collabAddr = (action.collaboratorAddress || target);
|
|
869
|
-
const role = action.role || "editor";
|
|
870
|
-
if (projId && collabAddr) {
|
|
871
|
-
await runtime.projects.addCollaborator(projId, collabAddr, role);
|
|
872
|
-
}
|
|
873
|
-
break;
|
|
874
|
-
}
|
|
875
|
-
case "link_project_to_guild":
|
|
876
|
-
case "link_project_to_clique": {
|
|
877
|
-
const projId2 = (action.projectId || signal.projectId);
|
|
878
|
-
const gId = (action.guildId || action.cliqueId);
|
|
879
|
-
if (projId2 && gId != null) {
|
|
880
|
-
await runtime.guilds.linkProject(Number(gId), projId2);
|
|
881
|
-
await runtime.projects.setGuildAttribution(projId2, String(gId));
|
|
882
|
-
// Gateway returns members as [{address, status}] objects where status=2 = accepted
|
|
883
|
-
const guild = await runtime.guilds.get(Number(gId));
|
|
884
|
-
const rawMembers = (guild?.members ?? []);
|
|
885
|
-
const myAddr = runtime.connection.address?.toLowerCase();
|
|
886
|
-
for (const m of rawMembers) {
|
|
887
|
-
if (typeof m === "string")
|
|
888
|
-
continue; // bare string — can't confirm accepted
|
|
889
|
-
if (m.status === 2 && m.address?.toLowerCase() !== myAddr) {
|
|
890
|
-
try {
|
|
891
|
-
await runtime.projects.addCollaborator(projId2, m.address, "editor");
|
|
892
|
-
}
|
|
893
|
-
catch { /* best-effort */ }
|
|
894
|
-
}
|
|
895
|
-
}
|
|
896
|
-
log(`[reactive] Linked project ${projId2} to guild ${gId}`);
|
|
897
|
-
}
|
|
898
|
-
break;
|
|
899
|
-
}
|
|
900
|
-
case "propose_guild":
|
|
901
|
-
case "propose_clique": {
|
|
902
|
-
const guildName = action.name || content;
|
|
903
|
-
const guildMembers2 = action.members;
|
|
904
|
-
const guildDesc = action.description || "";
|
|
905
|
-
if (guildName && guildMembers2 && guildMembers2.length >= 2) {
|
|
906
|
-
const relay = await prepareSignRelay(runtime.connection, "/v1/prepare/guild", { name: guildName, description: guildDesc, members: guildMembers2 });
|
|
907
|
-
log(`[reactive] Proposed guild "${guildName}" (tx: ${relay.txHash})`);
|
|
908
|
-
}
|
|
909
|
-
break;
|
|
910
|
-
}
|
|
911
|
-
case "join_guild":
|
|
912
|
-
case "approve_guild": {
|
|
913
|
-
const gId = action.guildId;
|
|
914
|
-
if (gId) {
|
|
915
|
-
const relay = await prepareSignRelay(runtime.connection, `/v1/prepare/guild/${gId}/approve`, {});
|
|
916
|
-
log(`[reactive] Approved guild #${gId} membership (tx: ${relay.txHash})`);
|
|
917
|
-
}
|
|
918
|
-
break;
|
|
919
|
-
}
|
|
920
|
-
case "reject_guild": {
|
|
921
|
-
const gId = action.guildId;
|
|
922
|
-
if (gId) {
|
|
923
|
-
const relay = await prepareSignRelay(runtime.connection, `/v1/prepare/guild/${gId}/reject`, {});
|
|
924
|
-
log(`[reactive] Rejected guild #${gId} membership (tx: ${relay.txHash})`);
|
|
925
|
-
}
|
|
926
|
-
break;
|
|
927
|
-
}
|
|
928
|
-
case "leave_guild": {
|
|
929
|
-
const gId = action.guildId;
|
|
930
|
-
if (gId) {
|
|
931
|
-
const relay = await prepareSignRelay(runtime.connection, `/v1/prepare/guild/${gId}/leave`, {});
|
|
932
|
-
log(`[reactive] Left guild #${gId} (tx: ${relay.txHash})`);
|
|
933
|
-
}
|
|
934
|
-
break;
|
|
935
|
-
}
|
|
936
|
-
case "publish":
|
|
937
|
-
case "create_post": {
|
|
938
|
-
const community = action.community || "general";
|
|
939
|
-
const title = action.title || content?.slice(0, 100) || "Untitled";
|
|
940
|
-
const body = content || "";
|
|
941
|
-
if (body) {
|
|
942
|
-
await runtime.memory.publishKnowledge({ title, body, community });
|
|
943
|
-
}
|
|
944
|
-
break;
|
|
945
|
-
}
|
|
946
|
-
case "execute":
|
|
947
|
-
if (channelId && content) {
|
|
948
|
-
await runtime.channels.send(channelId, content);
|
|
949
|
-
}
|
|
950
|
-
else if (target && content) {
|
|
951
|
-
await runtime.inbox.send({ to: target, content });
|
|
952
|
-
}
|
|
953
|
-
break;
|
|
954
|
-
case "accept": {
|
|
955
|
-
const projId = (action.projectId || signal.projectId);
|
|
956
|
-
const channelSlug = projId ? `project-${projId}` : "";
|
|
957
|
-
if (channelSlug) {
|
|
958
|
-
await runtime.channels.send(channelSlug, content || "Accepted the task — I'll get started.");
|
|
959
|
-
}
|
|
960
|
-
break;
|
|
961
|
-
}
|
|
962
|
-
case "acknowledge": {
|
|
963
|
-
const projId = (action.projectId || signal.projectId);
|
|
964
|
-
const channelSlug = projId ? `project-${projId}` : "";
|
|
965
|
-
if (channelSlug) {
|
|
966
|
-
await runtime.channels.send(channelSlug, content || "Got it, thanks for the mention!");
|
|
967
|
-
}
|
|
968
|
-
break;
|
|
969
|
-
}
|
|
970
|
-
case "deploy_preview": {
|
|
971
|
-
const projId = (action.projectId || signal.projectId);
|
|
972
|
-
if (projId) {
|
|
973
|
-
const relay = await prepareSignRelay(runtime.connection, `/v1/prepare/project/${projId}/deployment`, { prepaidHours: action.prepaidHours ?? 2 });
|
|
974
|
-
log(`[reactive] Deploy preview for ${projId} (tx: ${relay.txHash})`);
|
|
975
|
-
}
|
|
976
|
-
break;
|
|
977
|
-
}
|
|
978
|
-
case "fork_project": {
|
|
979
|
-
const projId = (action.projectId || signal.projectId);
|
|
980
|
-
if (projId) {
|
|
981
|
-
const res = await runtime.projects.forkProject(projId, {
|
|
982
|
-
name: action.name,
|
|
983
|
-
});
|
|
984
|
-
log(`[reactive] Forked project ${projId} → ${res.projectId}`);
|
|
985
|
-
}
|
|
986
|
-
break;
|
|
987
|
-
}
|
|
988
|
-
case "create_merge_request": {
|
|
989
|
-
const srcId = (action.sourceProjectId || signal.projectId);
|
|
990
|
-
const tgtId = action.targetProjectId;
|
|
991
|
-
const mrTitle = action.title;
|
|
992
|
-
const commitIds = action.commitIds;
|
|
993
|
-
if (srcId && tgtId && mrTitle && commitIds?.length) {
|
|
994
|
-
const mr = await runtime.projects.createMergeRequest(srcId, tgtId, mrTitle, commitIds, action.description);
|
|
995
|
-
log(`[reactive] Created merge request "${mrTitle}" (${mr.id})`);
|
|
996
|
-
}
|
|
997
|
-
break;
|
|
998
|
-
}
|
|
999
|
-
case "list_merge_requests": {
|
|
1000
|
-
const projId = (action.projectId || signal.projectId);
|
|
1001
|
-
if (projId) {
|
|
1002
|
-
const res = await runtime.projects.listMergeRequests(projId, {
|
|
1003
|
-
status: action.status,
|
|
1004
|
-
});
|
|
1005
|
-
log(`[reactive] Listed ${res.mergeRequests.length} merge requests on ${projId}`);
|
|
1006
|
-
}
|
|
1007
|
-
break;
|
|
1008
|
-
}
|
|
1009
|
-
case "get_merge_request": {
|
|
1010
|
-
const projId = (action.projectId || signal.projectId);
|
|
1011
|
-
const mrId = action.mrId;
|
|
1012
|
-
if (projId && mrId) {
|
|
1013
|
-
const mr = await runtime.projects.getMergeRequest(projId, mrId);
|
|
1014
|
-
log(`[reactive] Got merge request "${mr.title}" (${mr.status})`);
|
|
1015
|
-
}
|
|
1016
|
-
break;
|
|
1017
|
-
}
|
|
1018
|
-
case "merge_merge_request": {
|
|
1019
|
-
const projId = (action.projectId || signal.projectId);
|
|
1020
|
-
const mrId = action.mrId;
|
|
1021
|
-
if (projId && mrId) {
|
|
1022
|
-
await runtime.projects.mergeMergeRequest(projId, mrId, action.comment);
|
|
1023
|
-
log(`[reactive] Merged MR ${mrId} into ${projId}`);
|
|
1024
|
-
}
|
|
1025
|
-
break;
|
|
1026
|
-
}
|
|
1027
|
-
case "close_merge_request": {
|
|
1028
|
-
const projId = (action.projectId || signal.projectId);
|
|
1029
|
-
const mrId = action.mrId;
|
|
1030
|
-
if (projId && mrId) {
|
|
1031
|
-
await runtime.projects.closeMergeRequest(projId, mrId, action.comment);
|
|
1032
|
-
log(`[reactive] Closed MR ${mrId}`);
|
|
1033
|
-
}
|
|
1034
|
-
break;
|
|
1035
|
-
}
|
|
1036
|
-
case "claim_reward": {
|
|
1037
|
-
const pool = action.pool || "nook";
|
|
1038
|
-
const relay = await prepareSignRelay(runtime.connection, "/v1/prepare/reward/claim", { pool });
|
|
1039
|
-
log(`[reactive] Reward claimed from ${pool} pool (tx: ${relay.txHash})`);
|
|
1040
|
-
break;
|
|
1041
|
-
}
|
|
1042
|
-
case "create_task": {
|
|
1043
|
-
const projId = (action.projectId || signal.projectId);
|
|
1044
|
-
const title = (content || action.title);
|
|
1045
|
-
if (projId && title) {
|
|
1046
|
-
await runtime.connection.request("POST", `/v1/projects/${projId}/tasks`, {
|
|
1047
|
-
title,
|
|
1048
|
-
description: action.description,
|
|
1049
|
-
milestoneId: action.milestoneId,
|
|
1050
|
-
priority: action.priority ?? "medium",
|
|
1051
|
-
labels: action.labels,
|
|
1052
|
-
dueDate: action.dueDate,
|
|
1053
|
-
});
|
|
1054
|
-
log(`[reactive] Task created in ${projId}: ${title}`);
|
|
1055
|
-
}
|
|
1056
|
-
break;
|
|
1057
|
-
}
|
|
1058
|
-
case "assign_task": {
|
|
1059
|
-
const projId = (action.projectId || signal.projectId);
|
|
1060
|
-
const tid = (action.taskId);
|
|
1061
|
-
const assignee = (action.assigneeAddress || action.assignee);
|
|
1062
|
-
if (projId && tid && assignee) {
|
|
1063
|
-
await runtime.projects.assignTask(projId, tid, assignee);
|
|
1064
|
-
log(`[reactive] Assigned task ${tid} in ${projId} to ${assignee}`);
|
|
1065
|
-
}
|
|
1066
|
-
break;
|
|
1067
|
-
}
|
|
1068
|
-
case "complete_task":
|
|
1069
|
-
case "update_task": {
|
|
1070
|
-
const projId = (action.projectId || signal.projectId);
|
|
1071
|
-
const tid = action.taskId;
|
|
1072
|
-
if (projId && tid) {
|
|
1073
|
-
const updates = {};
|
|
1074
|
-
if (action.action === "complete_task") {
|
|
1075
|
-
updates.status = "completed";
|
|
1076
|
-
}
|
|
1077
|
-
else {
|
|
1078
|
-
if (action.status)
|
|
1079
|
-
updates.status = action.status;
|
|
1080
|
-
if (action.title)
|
|
1081
|
-
updates.title = action.title;
|
|
1082
|
-
if (action.description)
|
|
1083
|
-
updates.description = action.description;
|
|
1084
|
-
if (action.priority)
|
|
1085
|
-
updates.priority = action.priority;
|
|
1086
|
-
if (action.milestoneId !== undefined)
|
|
1087
|
-
updates.milestoneId = action.milestoneId;
|
|
1088
|
-
if (action.labels)
|
|
1089
|
-
updates.labels = action.labels;
|
|
1090
|
-
if (action.dueDate)
|
|
1091
|
-
updates.dueDate = action.dueDate;
|
|
1092
|
-
}
|
|
1093
|
-
await runtime.connection.request("PATCH", `/v1/projects/${projId}/tasks/${tid}`, updates);
|
|
1094
|
-
log(`[reactive] Task ${action.action === "complete_task" ? "completed" : "updated"}: ${tid}`);
|
|
1095
|
-
}
|
|
1096
|
-
break;
|
|
1097
|
-
}
|
|
1098
|
-
case "find_agents":
|
|
1099
|
-
case "find_matching_agents": {
|
|
1100
|
-
const skills = action.skills ?? [];
|
|
1101
|
-
if (skills.length) {
|
|
1102
|
-
const matchResult = await runtime.matching.findAgents(skills, {
|
|
1103
|
-
count: action.count,
|
|
1104
|
-
});
|
|
1105
|
-
log(`[reactive] Found ${matchResult.total} matching agents for [${skills.join(", ")}]`);
|
|
1106
|
-
}
|
|
1107
|
-
break;
|
|
1108
|
-
}
|
|
1109
|
-
case "assemble_team": {
|
|
1110
|
-
const desc = content || action.description || "";
|
|
1111
|
-
if (desc) {
|
|
1112
|
-
const teamResult = await runtime.matching.assembleTeam({
|
|
1113
|
-
description: desc,
|
|
1114
|
-
requiredSkills: action.requiredSkills,
|
|
1115
|
-
teamSize: action.teamSize,
|
|
1116
|
-
});
|
|
1117
|
-
log(`[reactive] Team assembled: ${teamResult.members.length} members, ${Math.round(teamResult.coverageScore * 100)}% coverage`);
|
|
1118
|
-
}
|
|
1119
|
-
break;
|
|
1120
|
-
}
|
|
1121
|
-
case "accept_invitation":
|
|
1122
|
-
case "decline_invitation": {
|
|
1123
|
-
const invId = (action.invitationId || signal.invitationId);
|
|
1124
|
-
if (invId) {
|
|
1125
|
-
const verb = action.action === "accept_invitation" ? "accept" : "decline";
|
|
1126
|
-
await runtime.connection.request("POST", `/v1/teams/invitations/${invId}/${verb}`, {});
|
|
1127
|
-
log(`[reactive] Team invitation ${verb}ed: ${invId.slice(0, 8)}...`);
|
|
1128
|
-
}
|
|
1129
|
-
break;
|
|
1130
|
-
}
|
|
1131
|
-
// ── Marketplace actions ──
|
|
1132
|
-
case "create_listing":
|
|
1133
|
-
case "list_service": {
|
|
1134
|
-
const title = (content || action.title);
|
|
1135
|
-
const desc = action.description || "";
|
|
1136
|
-
const category = action.category || "general";
|
|
1137
|
-
if (title) {
|
|
1138
|
-
const relay = await prepareSignRelay(runtime.connection, "/v1/prepare/service/list", {
|
|
1139
|
-
title, description: desc, category,
|
|
1140
|
-
pricingModel: action.pricingModel ?? 0,
|
|
1141
|
-
priceAmount: action.priceAmount ?? "0",
|
|
1142
|
-
tags: action.tags ?? [],
|
|
1143
|
-
...(action.tokenAddress ? { tokenAddress: action.tokenAddress } : {}),
|
|
1144
|
-
});
|
|
1145
|
-
log(`[reactive] Listed service "${title}" (tx: ${relay.txHash})`);
|
|
1146
|
-
}
|
|
1147
|
-
break;
|
|
1148
|
-
}
|
|
1149
|
-
case "create_agreement": {
|
|
1150
|
-
const listingId = action.listingId;
|
|
1151
|
-
const terms = (content || action.terms);
|
|
1152
|
-
const deadline = (action.deadline ?? Math.floor(Date.now() / 1000) + 7 * 86400);
|
|
1153
|
-
if (listingId != null && terms) {
|
|
1154
|
-
const relay = await prepareSignRelay(runtime.connection, "/v1/prepare/service/agree", {
|
|
1155
|
-
listingId, terms, deadline,
|
|
1156
|
-
tokenAmount: action.tokenAmount ?? "0",
|
|
1157
|
-
...(action.tokenAddress ? { tokenAddress: action.tokenAddress } : {}),
|
|
1158
|
-
});
|
|
1159
|
-
log(`[reactive] Created agreement for listing #${listingId} (tx: ${relay.txHash})`);
|
|
1160
|
-
}
|
|
1161
|
-
break;
|
|
1162
|
-
}
|
|
1163
|
-
case "deliver_work": {
|
|
1164
|
-
const agId = action.agreementId;
|
|
1165
|
-
const deliveryCid = (content || action.deliveryCid);
|
|
1166
|
-
if (agId != null && deliveryCid) {
|
|
1167
|
-
const relay = await prepareSignRelay(runtime.connection, "/v1/prepare/service/deliver", {
|
|
1168
|
-
agreementId: agId, deliveryCid,
|
|
1169
|
-
});
|
|
1170
|
-
log(`[reactive] Delivered work for agreement #${agId} (tx: ${relay.txHash})`);
|
|
1171
|
-
}
|
|
1172
|
-
break;
|
|
1173
|
-
}
|
|
1174
|
-
case "settle_agreement": {
|
|
1175
|
-
const agId = action.agreementId;
|
|
1176
|
-
if (agId != null) {
|
|
1177
|
-
const relay = await prepareSignRelay(runtime.connection, "/v1/prepare/service/settle", {
|
|
1178
|
-
agreementId: agId,
|
|
1179
|
-
});
|
|
1180
|
-
log(`[reactive] Settled agreement #${agId} (tx: ${relay.txHash})`);
|
|
1181
|
-
}
|
|
1182
|
-
break;
|
|
1183
|
-
}
|
|
1184
|
-
case "dispute_agreement": {
|
|
1185
|
-
const agId = action.agreementId;
|
|
1186
|
-
if (agId != null) {
|
|
1187
|
-
const relay = await prepareSignRelay(runtime.connection, "/v1/prepare/service/dispute", {
|
|
1188
|
-
agreementId: agId,
|
|
1189
|
-
});
|
|
1190
|
-
log(`[reactive] Disputed agreement #${agId} (tx: ${relay.txHash})`);
|
|
1191
|
-
}
|
|
1192
|
-
break;
|
|
1193
|
-
}
|
|
1194
|
-
case "cancel_agreement": {
|
|
1195
|
-
const agId = action.agreementId;
|
|
1196
|
-
if (agId != null) {
|
|
1197
|
-
const relay = await prepareSignRelay(runtime.connection, "/v1/prepare/service/cancel", {
|
|
1198
|
-
agreementId: agId,
|
|
1199
|
-
});
|
|
1200
|
-
log(`[reactive] Cancelled agreement #${agId} (tx: ${relay.txHash})`);
|
|
1201
|
-
}
|
|
1202
|
-
break;
|
|
1203
|
-
}
|
|
1204
|
-
case "submit_review": {
|
|
1205
|
-
const agId = action.agreementId;
|
|
1206
|
-
const rating = action.rating;
|
|
1207
|
-
const reviewComment = (content || action.comment || "");
|
|
1208
|
-
if (agId != null && rating != null) {
|
|
1209
|
-
await runtime.marketplace.submitReview(agId, rating, reviewComment);
|
|
1210
|
-
log(`[reactive] Submitted review for agreement #${agId} (${rating}/5)`);
|
|
1211
|
-
}
|
|
1212
|
-
break;
|
|
1213
|
-
}
|
|
1214
|
-
case "send_agreement_message": {
|
|
1215
|
-
const agId = action.agreementId;
|
|
1216
|
-
const msgType = action.messageType || "general";
|
|
1217
|
-
const msgContent = (content || action.content);
|
|
1218
|
-
if (agId != null && msgContent) {
|
|
1219
|
-
const msgBody = { messageType: msgType, content: msgContent };
|
|
1220
|
-
if (action.attachmentCid)
|
|
1221
|
-
msgBody.attachmentCid = action.attachmentCid;
|
|
1222
|
-
await runtime.connection.request("POST", `/v1/marketplace/agreements/${agId}/messages`, msgBody);
|
|
1223
|
-
log(`[reactive] Sent ${msgType} message for agreement #${agId}`);
|
|
1224
|
-
}
|
|
1225
|
-
break;
|
|
1226
|
-
}
|
|
1227
|
-
case "create_bounty": {
|
|
1228
|
-
const payload = action;
|
|
1229
|
-
const title = payload?.title;
|
|
1230
|
-
const description = payload?.description ?? content ?? "";
|
|
1231
|
-
const community = payload?.community ?? "";
|
|
1232
|
-
const deadline = payload?.deadline ?? Math.floor(Date.now() / 1000) + 604800; // 7 days
|
|
1233
|
-
const tokenRewardAmount = payload?.tokenRewardAmount ?? "0";
|
|
1234
|
-
if (!title)
|
|
1235
|
-
throw new Error("create_bounty requires title");
|
|
1236
|
-
const relay = await prepareSignRelay(runtime.connection, "/v1/prepare/bounty", {
|
|
1237
|
-
title, description, community, deadline, tokenRewardAmount,
|
|
1238
|
-
});
|
|
1239
|
-
log(`[reactive] Created bounty "${title}" (tx: ${relay.txHash})`);
|
|
1240
|
-
break;
|
|
1241
|
-
}
|
|
1242
|
-
case "post_reply": {
|
|
1243
|
-
const parentCid = (action.parentCid ?? action.sourceId ?? "");
|
|
1244
|
-
if (!parentCid)
|
|
1245
|
-
throw new Error("post_reply requires parentCid");
|
|
1246
|
-
const replyContent = (content ?? action.body ?? "");
|
|
1247
|
-
const replyCommunity = (action.community ?? "");
|
|
1248
|
-
await runtime.memory.publishComment({ parentCid, body: replyContent, community: replyCommunity });
|
|
1249
|
-
break;
|
|
1250
|
-
}
|
|
1251
|
-
case "propose_collab": {
|
|
1252
|
-
const collabTarget = (action.targetAddress ?? action.recipientAddress ?? target);
|
|
1253
|
-
if (!collabTarget)
|
|
1254
|
-
throw new Error("propose_collab requires targetAddress");
|
|
1255
|
-
const msg = content || "I'd like to collaborate with you!";
|
|
1256
|
-
await runtime.inbox.send({ to: collabTarget, content: msg });
|
|
1257
|
-
break;
|
|
1258
|
-
}
|
|
1259
|
-
case "create_bundle": {
|
|
1260
|
-
const bundleTitle = action.title;
|
|
1261
|
-
if (!bundleTitle)
|
|
1262
|
-
throw new Error("create_bundle requires title");
|
|
1263
|
-
const bundleDesc = content || action.description || "";
|
|
1264
|
-
const domain = action.domain || "";
|
|
1265
|
-
const relay = await prepareSignRelay(runtime.connection, "/v1/prepare/bundle", {
|
|
1266
|
-
title: bundleTitle, description: bundleDesc, domain,
|
|
1267
|
-
});
|
|
1268
|
-
log(`[reactive] Created bundle "${bundleTitle}" (tx: ${relay.txHash})`);
|
|
1269
|
-
break;
|
|
1270
|
-
}
|
|
1271
|
-
case "update_service": {
|
|
1272
|
-
const listingId = action.listingId;
|
|
1273
|
-
if (!listingId)
|
|
1274
|
-
throw new Error("update_service requires listingId");
|
|
1275
|
-
const relay = await prepareSignRelay(runtime.connection, "/v1/prepare/service/update", {
|
|
1276
|
-
listingId, ...action,
|
|
1277
|
-
});
|
|
1278
|
-
log(`[reactive] Updated service listing #${listingId} (tx: ${relay.txHash})`);
|
|
1279
|
-
break;
|
|
1280
|
-
}
|
|
1281
|
-
case "approve_bounty_work": {
|
|
1282
|
-
const bountyId = (action.bountyId || signal.bountyId);
|
|
1283
|
-
if (!bountyId)
|
|
1284
|
-
throw new Error("approve_bounty_work requires bountyId");
|
|
1285
|
-
const relay = await prepareSignRelay(runtime.connection, `/v1/prepare/bounty/${bountyId}/approve`, {});
|
|
1286
|
-
log(`[reactive] Approved bounty work: ${bountyId} (tx: ${relay.txHash})`);
|
|
1287
|
-
break;
|
|
1288
|
-
}
|
|
1289
|
-
case "dispute_bounty_work": {
|
|
1290
|
-
const bountyId = (action.bountyId || signal.bountyId);
|
|
1291
|
-
if (!bountyId)
|
|
1292
|
-
throw new Error("dispute_bounty_work requires bountyId");
|
|
1293
|
-
const relay = await prepareSignRelay(runtime.connection, `/v1/prepare/bounty/${bountyId}/dispute`, {});
|
|
1294
|
-
log(`[reactive] Disputed bounty work: ${bountyId} (tx: ${relay.txHash})`);
|
|
1295
|
-
break;
|
|
1296
|
-
}
|
|
1297
|
-
case "cancel_bounty": {
|
|
1298
|
-
const bountyId = (action.bountyId || signal.bountyId);
|
|
1299
|
-
if (!bountyId)
|
|
1300
|
-
throw new Error("cancel_bounty requires bountyId");
|
|
1301
|
-
const relay = await prepareSignRelay(runtime.connection, `/v1/prepare/bounty/${bountyId}/cancel`, {});
|
|
1302
|
-
log(`[reactive] Cancelled bounty: ${bountyId} (tx: ${relay.txHash})`);
|
|
1303
|
-
break;
|
|
1304
|
-
}
|
|
1305
|
-
case "unclaim_bounty": {
|
|
1306
|
-
const bountyId = (action.bountyId || signal.bountyId);
|
|
1307
|
-
if (!bountyId)
|
|
1308
|
-
throw new Error("unclaim_bounty requires bountyId");
|
|
1309
|
-
const relay = await prepareSignRelay(runtime.connection, `/v1/prepare/bounty/${bountyId}/unclaim`, {});
|
|
1310
|
-
log(`[reactive] Unclaimed bounty: ${bountyId} (tx: ${relay.txHash})`);
|
|
1311
|
-
break;
|
|
1312
|
-
}
|
|
1313
|
-
case "expire_dispute": {
|
|
1314
|
-
const agId = action.agreementId;
|
|
1315
|
-
if (agId != null) {
|
|
1316
|
-
const relay = await prepareSignRelay(runtime.connection, "/v1/prepare/service/expire-dispute", {
|
|
1317
|
-
agreementId: agId,
|
|
1318
|
-
});
|
|
1319
|
-
log(`[reactive] Expired dispute for agreement #${agId} (tx: ${relay.txHash})`);
|
|
1320
|
-
}
|
|
1321
|
-
break;
|
|
1322
|
-
}
|
|
1323
|
-
case "expire_delivered": {
|
|
1324
|
-
const agId = action.agreementId;
|
|
1325
|
-
if (agId != null) {
|
|
1326
|
-
const relay = await prepareSignRelay(runtime.connection, "/v1/prepare/service/expire-delivered", {
|
|
1327
|
-
agreementId: agId,
|
|
1328
|
-
});
|
|
1329
|
-
log(`[reactive] Expired delivered for agreement #${agId} (tx: ${relay.txHash})`);
|
|
1330
|
-
}
|
|
1331
|
-
break;
|
|
1332
|
-
}
|
|
1333
|
-
case "workspace_create": {
|
|
1334
|
-
const wsName = (action.name || content);
|
|
1335
|
-
if (wsName) {
|
|
1336
|
-
const ws = await runtime.workspaces.create({ name: wsName, description: action.description });
|
|
1337
|
-
log(`[reactive] Created workspace: ${ws.id}`);
|
|
1338
|
-
}
|
|
1339
|
-
break;
|
|
1340
|
-
}
|
|
1341
|
-
case "workspace_set": {
|
|
1342
|
-
const wsId = action.workspaceId;
|
|
1343
|
-
const wsKey = action.key;
|
|
1344
|
-
const wsVal = action.value ?? content;
|
|
1345
|
-
if (wsId && wsKey) {
|
|
1346
|
-
await runtime.workspaces.setState(wsId, wsKey, wsVal);
|
|
1347
|
-
log(`[reactive] Set ${wsKey} in workspace ${wsId}`);
|
|
1348
|
-
}
|
|
1349
|
-
break;
|
|
1350
|
-
}
|
|
1351
|
-
case "workspace_snapshot": {
|
|
1352
|
-
const wsId = action.workspaceId;
|
|
1353
|
-
if (wsId) {
|
|
1354
|
-
await runtime.workspaces.createSnapshot(wsId, action.label);
|
|
1355
|
-
log(`[reactive] Created snapshot in workspace ${wsId}`);
|
|
1356
|
-
}
|
|
1357
|
-
break;
|
|
1358
|
-
}
|
|
1359
|
-
case "propose_action": {
|
|
1360
|
-
const wsId = action.workspaceId;
|
|
1361
|
-
const title = (action.title || content);
|
|
1362
|
-
if (wsId && title) {
|
|
1363
|
-
const prop = await runtime.workspaces.createProposal(wsId, {
|
|
1364
|
-
title,
|
|
1365
|
-
description: action.description,
|
|
1366
|
-
actionType: action.actionType ?? "custom",
|
|
1367
|
-
actionPayload: action.actionPayload,
|
|
1368
|
-
quorumType: action.quorumType,
|
|
1369
|
-
quorumThreshold: action.quorumThreshold,
|
|
1370
|
-
});
|
|
1371
|
-
log(`[reactive] Created proposal: ${prop.proposal?.id}`);
|
|
1372
|
-
}
|
|
1373
|
-
break;
|
|
1374
|
-
}
|
|
1375
|
-
case "vote_proposal": {
|
|
1376
|
-
const wsId = action.workspaceId;
|
|
1377
|
-
const proposalId = action.proposalId;
|
|
1378
|
-
if (wsId && proposalId && action.vote !== undefined) {
|
|
1379
|
-
await runtime.workspaces.vote(wsId, proposalId, action.vote, action.reason);
|
|
1380
|
-
log(`[reactive] Voted on proposal ${proposalId}`);
|
|
1381
|
-
}
|
|
1382
|
-
break;
|
|
1383
|
-
}
|
|
1384
|
-
case "cancel_proposal": {
|
|
1385
|
-
const wsId = action.workspaceId;
|
|
1386
|
-
const proposalId = action.proposalId;
|
|
1387
|
-
if (wsId && proposalId) {
|
|
1388
|
-
await runtime.workspaces.cancelProposal(wsId, proposalId);
|
|
1389
|
-
log(`[reactive] Cancelled proposal ${proposalId}`);
|
|
1390
|
-
}
|
|
1391
|
-
break;
|
|
1392
|
-
}
|
|
1393
|
-
// ── Real World Actions ──
|
|
1394
|
-
case "egress_request":
|
|
1395
|
-
case "http_request": {
|
|
1396
|
-
const targetUrl = action.url ?? "";
|
|
1397
|
-
const httpMethod = (action.method ?? "GET").toUpperCase();
|
|
1398
|
-
if (!targetUrl)
|
|
1399
|
-
throw new Error("egress_request requires url");
|
|
1400
|
-
const httpResult = await runtime.tools.httpRequest(targetUrl, httpMethod, {
|
|
1401
|
-
headers: action.headers,
|
|
1402
|
-
body: action.body,
|
|
1403
|
-
timeout: action.timeout,
|
|
1404
|
-
credentialService: action.credentialService,
|
|
1405
|
-
});
|
|
1406
|
-
log(`[reactive] HTTP ${httpMethod} ${targetUrl.slice(0, 60)} → ${httpResult?.status ?? "ok"}`);
|
|
1407
|
-
break;
|
|
1408
|
-
}
|
|
1409
|
-
case "execute_tool": {
|
|
1410
|
-
const toolName = action.toolName ?? "";
|
|
1411
|
-
if (!toolName)
|
|
1412
|
-
throw new Error("execute_tool requires toolName");
|
|
1413
|
-
const toolArgs = (action.args ?? action.arguments ?? {});
|
|
1414
|
-
const toolResult = await runtime.tools.executeTool(toolName, toolArgs);
|
|
1415
|
-
log(`[reactive] Executed tool: ${toolName}`);
|
|
1416
|
-
break;
|
|
1417
|
-
}
|
|
1418
|
-
case "exec_code": {
|
|
1419
|
-
const cmd = action.command ?? "";
|
|
1420
|
-
const img = (action.image ?? "node:20-slim");
|
|
1421
|
-
const files = (action.files ?? {});
|
|
1422
|
-
const timeout = action.timeout;
|
|
1423
|
-
const projId = action.projectId;
|
|
1424
|
-
if (!cmd)
|
|
1425
|
-
throw new Error("exec_code requires command");
|
|
1426
|
-
const execResult = await runtime.tools.execCode(cmd, img, { files, timeout, projectId: projId });
|
|
1427
|
-
log(`[reactive] Executed code (${img}): exit=${execResult.exitCode}`);
|
|
1428
|
-
break;
|
|
1429
|
-
}
|
|
1430
|
-
case "connect_mcp_server": {
|
|
1431
|
-
const serverUrl = (action.serverUrl ?? action.url);
|
|
1432
|
-
const serverName = (action.serverName ?? action.name ?? "mcp-server");
|
|
1433
|
-
if (!serverUrl)
|
|
1434
|
-
throw new Error("connect_mcp_server requires serverUrl");
|
|
1435
|
-
await runtime.tools.connectMcpServer(serverUrl, serverName);
|
|
1436
|
-
log(`[reactive] Connected MCP server: ${serverUrl.slice(0, 60)}`);
|
|
1437
|
-
break;
|
|
1438
|
-
}
|
|
1439
|
-
case "disconnect_mcp_server": {
|
|
1440
|
-
const serverId = (action.serverId ?? action.serverUrl);
|
|
1441
|
-
if (!serverId)
|
|
1442
|
-
throw new Error("disconnect_mcp_server requires serverId");
|
|
1443
|
-
await runtime.tools.disconnectMcpServer(serverId);
|
|
1444
|
-
log(`[reactive] Disconnected MCP server: ${serverId.slice(0, 60)}`);
|
|
1445
|
-
break;
|
|
1446
|
-
}
|
|
1447
|
-
case "call_mcp_tool":
|
|
1448
|
-
case "use_mcp_tool": {
|
|
1449
|
-
const mcpToolName = action.toolName ?? "";
|
|
1450
|
-
if (!mcpToolName)
|
|
1451
|
-
throw new Error("call_mcp_tool requires toolName");
|
|
1452
|
-
const mcpToolArgs = (action.args ?? action.arguments ?? {});
|
|
1453
|
-
const mcpResult = await runtime.tools.executeTool(mcpToolName, mcpToolArgs);
|
|
1454
|
-
log(`[reactive] MCP tool called: ${mcpToolName}`);
|
|
1455
|
-
break;
|
|
1456
|
-
}
|
|
1457
|
-
case "register_webhook": {
|
|
1458
|
-
const source = action.source ?? "";
|
|
1459
|
-
if (!source)
|
|
1460
|
-
throw new Error("register_webhook requires source");
|
|
1461
|
-
await runtime.connection.request("POST", "/v1/agents/me/webhooks", {
|
|
1462
|
-
source,
|
|
1463
|
-
description: action.description,
|
|
1464
|
-
secret: action.secret,
|
|
1465
|
-
});
|
|
1466
|
-
log(`[reactive] Registered webhook: ${source}`);
|
|
1467
|
-
break;
|
|
1468
|
-
}
|
|
1469
|
-
case "publish_insight": {
|
|
1470
|
-
const title = action.title;
|
|
1471
|
-
const body = action.body;
|
|
1472
|
-
if (title && body) {
|
|
1473
|
-
await runtime.insights?.publish({
|
|
1474
|
-
title,
|
|
1475
|
-
body,
|
|
1476
|
-
strategyType: action.strategyType,
|
|
1477
|
-
tags: action.tags,
|
|
1478
|
-
outcomeScore: action.outcomeScore,
|
|
1479
|
-
workspaceId: action.workspaceId,
|
|
1480
|
-
});
|
|
1481
|
-
log(`[reactive] Published insight: ${title}`);
|
|
1482
|
-
}
|
|
1483
|
-
break;
|
|
1484
|
-
}
|
|
1485
|
-
case "cite_insight": {
|
|
1486
|
-
const insightId = action.insightId;
|
|
1487
|
-
if (insightId) {
|
|
1488
|
-
await runtime.insights?.cite(insightId, action.context, action.outcomeScore);
|
|
1489
|
-
log(`[reactive] Cited insight ${insightId}`);
|
|
1490
|
-
}
|
|
1491
|
-
break;
|
|
1492
|
-
}
|
|
1493
|
-
case "apply_insight": {
|
|
1494
|
-
const insightId = action.insightId;
|
|
1495
|
-
if (insightId) {
|
|
1496
|
-
await runtime.insights?.apply(insightId, action.context, action.outcomeScore);
|
|
1497
|
-
log(`[reactive] Applied insight ${insightId}`);
|
|
1498
|
-
}
|
|
1499
|
-
break;
|
|
1500
|
-
}
|
|
1501
|
-
case "deposit_treasury": {
|
|
1502
|
-
const guildId = action.guildId;
|
|
1503
|
-
const amount = action.amount;
|
|
1504
|
-
if (guildId && amount) {
|
|
1505
|
-
await runtime.guilds.depositTreasury(guildId, amount, action.memo);
|
|
1506
|
-
log(`[reactive] Deposited ${amount} to guild ${guildId} treasury`);
|
|
1507
|
-
}
|
|
1508
|
-
break;
|
|
1509
|
-
}
|
|
1510
|
-
case "withdraw_treasury": {
|
|
1511
|
-
const guildId = action.guildId;
|
|
1512
|
-
const amount = action.amount;
|
|
1513
|
-
if (guildId && amount) {
|
|
1514
|
-
await runtime.guilds.withdrawTreasury(guildId, amount, action.memo);
|
|
1515
|
-
log(`[reactive] Withdrew ${amount} from guild ${guildId} treasury`);
|
|
1516
|
-
}
|
|
1517
|
-
break;
|
|
1518
|
-
}
|
|
1519
|
-
case "fund_bounty_from_treasury": {
|
|
1520
|
-
const guildId = action.guildId;
|
|
1521
|
-
const bountyId = action.bountyId;
|
|
1522
|
-
const amount = action.amount;
|
|
1523
|
-
if (guildId && bountyId && amount) {
|
|
1524
|
-
await runtime.guilds.fundBountyFromTreasury(guildId, bountyId, amount, action.proposalId);
|
|
1525
|
-
log(`[reactive] Funded bounty ${bountyId} with ${amount} from guild ${guildId} treasury`);
|
|
1526
|
-
}
|
|
1527
|
-
break;
|
|
1528
|
-
}
|
|
1529
|
-
case "distribute_revenue": {
|
|
1530
|
-
const guildId = action.guildId;
|
|
1531
|
-
if (guildId) {
|
|
1532
|
-
await runtime.guilds.distributeRevenue(guildId, action.amount);
|
|
1533
|
-
log(`[reactive] Distributed revenue for guild ${guildId}`);
|
|
1534
|
-
}
|
|
1535
|
-
break;
|
|
1536
|
-
}
|
|
1537
|
-
case "create_swarm": {
|
|
1538
|
-
if (action.title && action.subtasks) {
|
|
1539
|
-
await runtime.swarms?.create({ title: action.title, description: action.description, workspaceId: action.workspaceId, subtasks: action.subtasks });
|
|
1540
|
-
log(`[reactive] Created swarm: ${action.title}`);
|
|
1541
|
-
}
|
|
1542
|
-
break;
|
|
1543
|
-
}
|
|
1544
|
-
case "claim_subtask": {
|
|
1545
|
-
const stId = action.subtaskId;
|
|
1546
|
-
if (stId) {
|
|
1547
|
-
await runtime.swarms?.claimSubtask(stId);
|
|
1548
|
-
log(`[reactive] Claimed subtask ${stId}`);
|
|
1549
|
-
}
|
|
1550
|
-
break;
|
|
1551
|
-
}
|
|
1552
|
-
case "submit_swarm_result": {
|
|
1553
|
-
const stId = action.subtaskId;
|
|
1554
|
-
if (stId && action.content) {
|
|
1555
|
-
await runtime.swarms?.submitResult(stId, action.content, action.resultType);
|
|
1556
|
-
log(`[reactive] Submitted result for subtask ${stId}`);
|
|
1557
|
-
}
|
|
1558
|
-
break;
|
|
1559
|
-
}
|
|
1560
|
-
case "aggregate_swarm": {
|
|
1561
|
-
const swarmId = action.swarmId;
|
|
1562
|
-
if (swarmId) {
|
|
1563
|
-
await runtime.swarms?.aggregate(swarmId, action.summary);
|
|
1564
|
-
log(`[reactive] Aggregated swarm ${swarmId}`);
|
|
1565
|
-
}
|
|
1566
|
-
break;
|
|
1567
|
-
}
|
|
1568
|
-
case "record_gap": {
|
|
1569
|
-
if (action.queryText) {
|
|
1570
|
-
await runtime.specialization?.recordGap({ queryText: action.queryText, queryTags: action.queryTags || [], communityId: action.communityId });
|
|
1571
|
-
log(`[reactive] Recorded skill gap: ${action.queryText}`);
|
|
1572
|
-
}
|
|
1573
|
-
break;
|
|
1574
|
-
}
|
|
1575
|
-
case "update_proficiency": {
|
|
1576
|
-
const domain = action.skillDomain;
|
|
1577
|
-
if (domain) {
|
|
1578
|
-
await runtime.specialization?.updateProficiency(domain, Number(action.proficiency || 0));
|
|
1579
|
-
log(`[reactive] Updated proficiency: ${domain}`);
|
|
1580
|
-
}
|
|
1581
|
-
break;
|
|
1582
|
-
}
|
|
1583
|
-
case "generate_recommendations": {
|
|
1584
|
-
await runtime.specialization?.generateRecommendations();
|
|
1585
|
-
log(`[reactive] Generated specialization recommendations`);
|
|
1586
|
-
break;
|
|
1587
|
-
}
|
|
1588
|
-
case "dismiss_recommendation": {
|
|
1589
|
-
const recId = action.recommendationId;
|
|
1590
|
-
if (recId) {
|
|
1591
|
-
await runtime.specialization?.dismissRecommendation(recId);
|
|
1592
|
-
log(`[reactive] Dismissed recommendation ${recId}`);
|
|
1593
|
-
}
|
|
1594
|
-
break;
|
|
1595
|
-
}
|
|
1596
|
-
// ── Intents ──
|
|
1597
|
-
case "create_intent": {
|
|
1598
|
-
const intentRes = await runtime.intents.create({
|
|
1599
|
-
title: action.title || action.content || "Untitled intent",
|
|
1600
|
-
description: action.description || action.content || "",
|
|
1601
|
-
requiredSkills: action.requiredSkills,
|
|
1602
|
-
budgetAmount: action.budgetAmount,
|
|
1603
|
-
category: action.category,
|
|
1604
|
-
tags: action.tags,
|
|
1605
|
-
});
|
|
1606
|
-
log(`[reactive] Created intent ${intentRes.id}`);
|
|
1607
|
-
break;
|
|
1608
|
-
}
|
|
1609
|
-
case "browse_intents": {
|
|
1610
|
-
const browseRes = await runtime.intents.list({
|
|
1611
|
-
status: action.status || "open",
|
|
1612
|
-
category: action.category,
|
|
1613
|
-
q: action.q,
|
|
1614
|
-
limit: 20,
|
|
1615
|
-
});
|
|
1616
|
-
log(`[reactive] Found ${browseRes.total} intents`);
|
|
1617
|
-
break;
|
|
1618
|
-
}
|
|
1619
|
-
case "submit_proposal": {
|
|
1620
|
-
const spIntentId = action.intentId;
|
|
1621
|
-
if (spIntentId) {
|
|
1622
|
-
const proposalRes = await runtime.intents.submitProposal(spIntentId, {
|
|
1623
|
-
description: action.description || action.content || "",
|
|
1624
|
-
approach: action.approach,
|
|
1625
|
-
estimatedCost: action.estimatedCost,
|
|
1626
|
-
estimatedDurationHours: action.estimatedDurationHours,
|
|
1627
|
-
});
|
|
1628
|
-
log(`[reactive] Submitted proposal ${proposalRes.id}`);
|
|
1629
|
-
}
|
|
1630
|
-
break;
|
|
1631
|
-
}
|
|
1632
|
-
case "accept_proposal": {
|
|
1633
|
-
const apIntentId = action.intentId;
|
|
1634
|
-
const apProposalId = action.proposalId;
|
|
1635
|
-
if (apIntentId && apProposalId) {
|
|
1636
|
-
await runtime.intents.acceptProposal(apIntentId, apProposalId);
|
|
1637
|
-
log(`[reactive] Accepted proposal ${apProposalId}`);
|
|
1638
|
-
}
|
|
1639
|
-
break;
|
|
1640
|
-
}
|
|
1641
|
-
case "reject_proposal": {
|
|
1642
|
-
const rpIntentId = action.intentId;
|
|
1643
|
-
const rpProposalId = action.proposalId;
|
|
1644
|
-
if (rpIntentId && rpProposalId) {
|
|
1645
|
-
const rpReason = action.content || action.reason || "";
|
|
1646
|
-
await runtime.intents.rejectProposal(rpIntentId, rpProposalId, rpReason);
|
|
1647
|
-
log(`[reactive] Rejected proposal ${rpProposalId}`);
|
|
1648
|
-
}
|
|
1649
|
-
break;
|
|
1650
|
-
}
|
|
1651
|
-
case "cancel_intent": {
|
|
1652
|
-
const ciId = action.intentId;
|
|
1653
|
-
if (ciId) {
|
|
1654
|
-
await runtime.intents.cancel(ciId);
|
|
1655
|
-
log(`[reactive] Cancelled intent ${ciId}`);
|
|
1656
|
-
}
|
|
1657
|
-
break;
|
|
1658
|
-
}
|
|
1659
|
-
case "complete_intent": {
|
|
1660
|
-
const coiId = action.intentId;
|
|
1661
|
-
if (coiId) {
|
|
1662
|
-
await runtime.intents.complete(coiId);
|
|
1663
|
-
log(`[reactive] Completed intent ${coiId}`);
|
|
1664
|
-
}
|
|
1665
|
-
break;
|
|
1666
|
-
}
|
|
1667
|
-
case "withdraw_proposal": {
|
|
1668
|
-
const wpIntentId = action.intentId;
|
|
1669
|
-
const wpProposalId = action.proposalId;
|
|
1670
|
-
if (wpIntentId && wpProposalId) {
|
|
1671
|
-
await runtime.intents.withdrawProposal(wpIntentId, wpProposalId);
|
|
1672
|
-
log(`[reactive] Withdrew proposal ${wpProposalId}`);
|
|
1673
|
-
}
|
|
1674
|
-
break;
|
|
1675
|
-
}
|
|
1676
|
-
case "query_oracle": {
|
|
1677
|
-
const oEntityType = action.entityType;
|
|
1678
|
-
const oEntityId = action.entityId;
|
|
1679
|
-
if (oEntityType && oEntityId) {
|
|
1680
|
-
let oracleRes;
|
|
1681
|
-
switch (oEntityType) {
|
|
1682
|
-
case "project":
|
|
1683
|
-
oracleRes = await runtime.oracle.getProjectSignals(oEntityId);
|
|
1684
|
-
break;
|
|
1685
|
-
case "agent":
|
|
1686
|
-
oracleRes = await runtime.oracle.getAgentSignals(oEntityId);
|
|
1687
|
-
break;
|
|
1688
|
-
case "intent":
|
|
1689
|
-
oracleRes = await runtime.oracle.getIntentSignals(oEntityId);
|
|
1690
|
-
break;
|
|
1691
|
-
case "guild":
|
|
1692
|
-
oracleRes = await runtime.oracle.getGuildSignals(oEntityId);
|
|
1693
|
-
break;
|
|
1694
|
-
}
|
|
1695
|
-
if (oracleRes)
|
|
1696
|
-
log(`[reactive] Oracle ${oEntityType}/${oEntityId}: ${JSON.stringify(oracleRes.signals).slice(0, 100)}`);
|
|
1697
|
-
}
|
|
1698
|
-
break;
|
|
1699
|
-
}
|
|
1700
|
-
case "create_search_subscription": {
|
|
1701
|
-
const subRes = await runtime.discovery.createSubscription({
|
|
1702
|
-
label: action.label || "Search subscription",
|
|
1703
|
-
query: action.query || action.content || "",
|
|
1704
|
-
types: action.types,
|
|
1705
|
-
frequencyMinutes: action.frequencyMinutes,
|
|
1706
|
-
});
|
|
1707
|
-
log(`[reactive] Created search subscription ${subRes.id}`);
|
|
1708
|
-
break;
|
|
1709
|
-
}
|
|
1710
|
-
// ── Clawnch Token Launching ──
|
|
1711
|
-
case "preview_token_launch": {
|
|
1712
|
-
const prevRes = await runtime.connection.request("POST", "/v1/clawnch/preview", { tokenName: action.tokenName, tokenTicker: action.tokenTicker, description: action.description || action.content, imageUrl: action.imageUrl });
|
|
1713
|
-
log(`[reactive] Token preview: ${prevRes?.launch ? "OK" : "done"}`);
|
|
1714
|
-
break;
|
|
1715
|
-
}
|
|
1716
|
-
case "launch_token": {
|
|
1717
|
-
const launchRes = await runtime.connection.request("POST", "/v1/clawnch/launch", { tokenName: action.tokenName, tokenTicker: action.tokenTicker, description: action.description || action.content, imageUrl: action.imageUrl });
|
|
1718
|
-
const tokenAddr = launchRes?.launch;
|
|
1719
|
-
log(`[reactive] Launched token ${tokenAddr?.token_address ?? "pending"}`);
|
|
1720
|
-
break;
|
|
1721
|
-
}
|
|
1722
|
-
case "claim_clawnch_fees": {
|
|
1723
|
-
const claimAddr = action.tokenAddress;
|
|
1724
|
-
if (claimAddr) {
|
|
1725
|
-
const claimRes = await runtime.connection.request("POST", "/v1/clawnch/claim-fees", { tokenAddress: claimAddr });
|
|
1726
|
-
log(`[reactive] Claimed fees for ${claimAddr.slice(0, 10)}...`);
|
|
1727
|
-
}
|
|
1728
|
-
break;
|
|
1729
|
-
}
|
|
1730
|
-
case "get_token_analytics": {
|
|
1731
|
-
const analyticsAddr = action.tokenAddress;
|
|
1732
|
-
if (analyticsAddr) {
|
|
1733
|
-
const analyticsRes = await runtime.connection.request("GET", `/v1/clawnch/analytics/token/${analyticsAddr}`);
|
|
1734
|
-
log(`[reactive] Token analytics for ${analyticsAddr.slice(0, 10)}...`);
|
|
1735
|
-
}
|
|
1736
|
-
break;
|
|
1737
|
-
}
|
|
1738
|
-
case "send_email": {
|
|
1739
|
-
const emailTo = action.to;
|
|
1740
|
-
const subject = (action.subject || content?.slice(0, 100));
|
|
1741
|
-
const emailBody = (action.body || content);
|
|
1742
|
-
if (!emailTo || !subject || !emailBody)
|
|
1743
|
-
throw new Error("send_email requires to, subject, body");
|
|
1744
|
-
await runtime.connection.request("POST", "/v1/email/send", { to: emailTo, subject, bodyText: emailBody });
|
|
1745
|
-
log(`[reactive] Email sent to ${emailTo.slice(0, 30)}`);
|
|
1746
|
-
break;
|
|
1747
|
-
}
|
|
1748
|
-
case "reply_email": {
|
|
1749
|
-
const msgId = action.messageId;
|
|
1750
|
-
const replyBody = (action.body || content);
|
|
1751
|
-
if (!msgId || !replyBody)
|
|
1752
|
-
throw new Error("reply_email requires messageId and body");
|
|
1753
|
-
await runtime.connection.request("POST", `/v1/email/${msgId}/reply`, { bodyText: replyBody });
|
|
1754
|
-
log(`[reactive] Replied to email ${msgId.slice(0, 10)}...`);
|
|
1755
|
-
break;
|
|
1756
|
-
}
|
|
1757
|
-
case "check_email": {
|
|
1758
|
-
await runtime.connection.request("GET", "/v1/email/messages?direction=inbound&limit=10");
|
|
1759
|
-
log(`[reactive] Checked email inbox`);
|
|
1760
|
-
break;
|
|
1761
|
-
}
|
|
1762
|
-
case "create_email_inbox": {
|
|
1763
|
-
const localPart = action.username;
|
|
1764
|
-
if (!localPart)
|
|
1765
|
-
throw new Error("create_email_inbox requires username");
|
|
1766
|
-
await runtime.connection.request("POST", "/v1/email/inbox", { username: localPart, displayName: action.displayName });
|
|
1767
|
-
log(`[reactive] Created email inbox: ${localPart}`);
|
|
1768
|
-
break;
|
|
1769
|
-
}
|
|
1770
|
-
// ── Skill Registry ──────────────────────────────────────────────
|
|
1771
|
-
case "search_skills": {
|
|
1772
|
-
const q = action.query || action.q || "";
|
|
1773
|
-
const category = action.category;
|
|
1774
|
-
const limit = action.limit || 20;
|
|
1775
|
-
const params = new URLSearchParams();
|
|
1776
|
-
if (q)
|
|
1777
|
-
params.set("q", String(q));
|
|
1778
|
-
if (category)
|
|
1779
|
-
params.set("category", String(category));
|
|
1780
|
-
params.set("limit", String(limit));
|
|
1781
|
-
await runtime.connection.request("GET", `/v1/skills/registry?${params.toString()}`);
|
|
1782
|
-
log(`[reactive] Searched skills: "${q}"`);
|
|
1783
|
-
break;
|
|
1784
|
-
}
|
|
1785
|
-
case "publish_skill": {
|
|
1786
|
-
const name = action.name;
|
|
1787
|
-
if (!name)
|
|
1788
|
-
throw new Error("publish_skill requires name");
|
|
1789
|
-
await runtime.connection.request("POST", "/v1/skills/registry", {
|
|
1790
|
-
name,
|
|
1791
|
-
description: action.description,
|
|
1792
|
-
packageType: action.packageType || "skill_md",
|
|
1793
|
-
category: action.category || "other",
|
|
1794
|
-
tags: action.tags,
|
|
1795
|
-
content: action.content || content,
|
|
1796
|
-
githubUrl: action.githubUrl,
|
|
1797
|
-
npmPackage: action.npmPackage,
|
|
1798
|
-
version: action.version || "1.0.0",
|
|
1799
|
-
});
|
|
1800
|
-
log(`[reactive] Published skill: ${name}`);
|
|
1801
|
-
break;
|
|
1802
|
-
}
|
|
1803
|
-
case "install_skill": {
|
|
1804
|
-
const skillId = action.skillId || action.skill_id;
|
|
1805
|
-
if (!skillId)
|
|
1806
|
-
throw new Error("install_skill requires skillId");
|
|
1807
|
-
await runtime.connection.request("POST", `/v1/skills/registry/${skillId}/install`);
|
|
1808
|
-
log(`[reactive] Installed skill: ${skillId}`);
|
|
1809
|
-
break;
|
|
1810
|
-
}
|
|
1811
|
-
case "review_skill": {
|
|
1812
|
-
const skillId = action.skillId || action.skill_id;
|
|
1813
|
-
const rating = action.rating;
|
|
1814
|
-
if (!skillId || !rating)
|
|
1815
|
-
throw new Error("review_skill requires skillId and rating");
|
|
1816
|
-
await runtime.connection.request("POST", `/v1/skills/registry/${skillId}/review`, {
|
|
1817
|
-
rating, review: action.review || content,
|
|
1818
|
-
});
|
|
1819
|
-
log(`[reactive] Reviewed skill: ${skillId} (${rating}/5)`);
|
|
1820
|
-
break;
|
|
1821
|
-
}
|
|
1822
|
-
case "trending_skills": {
|
|
1823
|
-
const limit = action.limit || 20;
|
|
1824
|
-
await runtime.connection.request("GET", `/v1/skills/registry/trending?limit=${limit}`);
|
|
1825
|
-
log(`[reactive] Fetched trending skills`);
|
|
1826
|
-
break;
|
|
1827
|
-
}
|
|
1828
|
-
// ── Agent Memory ────────────────────────────────────────────────
|
|
1829
|
-
case "store_memory": {
|
|
1830
|
-
const memContent = action.body || content;
|
|
1831
|
-
if (!memContent)
|
|
1832
|
-
throw new Error("store_memory requires content");
|
|
1833
|
-
await runtime.connection.request("POST", "/v1/agent-memory/store", {
|
|
1834
|
-
type: action.memoryType || action.type || "semantic",
|
|
1835
|
-
content: memContent, importance: action.importance, tags: action.tags,
|
|
1836
|
-
source: action.source, metadata: action.metadata,
|
|
1837
|
-
});
|
|
1838
|
-
log(`[reactive] Stored memory`);
|
|
1839
|
-
break;
|
|
1840
|
-
}
|
|
1841
|
-
case "recall_memory": {
|
|
1842
|
-
const query = action.query || action.q;
|
|
1843
|
-
if (!query)
|
|
1844
|
-
throw new Error("recall_memory requires query");
|
|
1845
|
-
const rtypes = action.types
|
|
1846
|
-
|| ((action.memoryType || action.type) ? [String(action.memoryType || action.type)] : undefined);
|
|
1847
|
-
await runtime.connection.request("POST", "/v1/agent-memory/recall", {
|
|
1848
|
-
query, types: rtypes, limit: action.limit || 10,
|
|
1849
|
-
});
|
|
1850
|
-
log(`[reactive] Recalled memories for: "${query}"`);
|
|
1851
|
-
break;
|
|
1852
|
-
}
|
|
1853
|
-
case "list_memories": {
|
|
1854
|
-
const type = action.memoryType || action.type || "";
|
|
1855
|
-
const limit = action.limit || 20;
|
|
1856
|
-
const params = new URLSearchParams();
|
|
1857
|
-
if (type)
|
|
1858
|
-
params.set("type", String(type));
|
|
1859
|
-
params.set("limit", String(limit));
|
|
1860
|
-
await runtime.connection.request("GET", `/v1/agent-memory/list?${params.toString()}`);
|
|
1861
|
-
log(`[reactive] Listed memories`);
|
|
1862
|
-
break;
|
|
1863
|
-
}
|
|
1864
|
-
case "memory_stats": {
|
|
1865
|
-
await runtime.connection.request("GET", "/v1/agent-memory/stats");
|
|
1866
|
-
log(`[reactive] Fetched memory stats`);
|
|
1867
|
-
break;
|
|
1868
|
-
}
|
|
1869
|
-
case "export_memories": {
|
|
1870
|
-
await runtime.connection.request("POST", "/v1/agent-memory/export");
|
|
1871
|
-
log(`[reactive] Exported memories`);
|
|
1872
|
-
break;
|
|
1873
|
-
}
|
|
1874
|
-
case "import_memories": {
|
|
1875
|
-
const pack = action.pack || action.memories;
|
|
1876
|
-
if (!pack)
|
|
1877
|
-
throw new Error("import_memories requires pack data");
|
|
1878
|
-
await runtime.connection.request("POST", "/v1/agent-memory/import", pack);
|
|
1879
|
-
log(`[reactive] Imported memories`);
|
|
1880
|
-
break;
|
|
1881
|
-
}
|
|
1882
|
-
// ── Forge (Agent Deployment) ────────────────────────────────────
|
|
1883
|
-
case "forge_deploy": {
|
|
1884
|
-
const forgeBundleId = action.bundleId;
|
|
1885
|
-
const forgeAgentAddr = action.agentAddress;
|
|
1886
|
-
const forgeSoulCid = action.soulCid;
|
|
1887
|
-
if (!forgeBundleId)
|
|
1888
|
-
throw new Error("forge_deploy requires bundleId (number)");
|
|
1889
|
-
if (!forgeAgentAddr)
|
|
1890
|
-
throw new Error("forge_deploy requires agentAddress");
|
|
1891
|
-
if (!forgeSoulCid)
|
|
1892
|
-
throw new Error("forge_deploy requires soulCid");
|
|
1893
|
-
const relay = await prepareSignRelay(runtime.connection, "/v1/prepare/forge", {
|
|
1894
|
-
bundleId: forgeBundleId, agentAddress: forgeAgentAddr, soulCid: forgeSoulCid, deploymentFee: action.deploymentFee,
|
|
1895
|
-
});
|
|
1896
|
-
log(`[reactive] Forge deployed: ${forgeBundleId} (tx: ${relay.txHash})`);
|
|
1897
|
-
break;
|
|
1898
|
-
}
|
|
1899
|
-
case "forge_spawn": {
|
|
1900
|
-
const spawnBundleId = action.bundleId;
|
|
1901
|
-
const childAddress = action.childAddress || action.parentAddress;
|
|
1902
|
-
const spawnSoulCid = action.soulCid;
|
|
1903
|
-
if (!spawnBundleId)
|
|
1904
|
-
throw new Error("forge_spawn requires bundleId (number)");
|
|
1905
|
-
if (!childAddress)
|
|
1906
|
-
throw new Error("forge_spawn requires childAddress");
|
|
1907
|
-
if (!spawnSoulCid)
|
|
1908
|
-
throw new Error("forge_spawn requires soulCid");
|
|
1909
|
-
const relay = await prepareSignRelay(runtime.connection, "/v1/prepare/forge/spawn", {
|
|
1910
|
-
bundleId: spawnBundleId, childAddress, soulCid: spawnSoulCid, deploymentFee: action.deploymentFee,
|
|
1911
|
-
});
|
|
1912
|
-
log(`[reactive] Forge spawned child: ${childAddress} (tx: ${relay.txHash})`);
|
|
1913
|
-
break;
|
|
1914
|
-
}
|
|
1915
|
-
case "forge_update_soul": {
|
|
1916
|
-
const agentId = action.agentId || action.forgeId;
|
|
1917
|
-
if (!agentId)
|
|
1918
|
-
throw new Error("forge_update_soul requires agentId");
|
|
1919
|
-
const relay = await prepareSignRelay(runtime.connection, `/v1/prepare/forge/${agentId}/soul`, {
|
|
1920
|
-
soulCid: action.soulCid, metadata: action.metadata,
|
|
1921
|
-
});
|
|
1922
|
-
log(`[reactive] Forge soul updated: ${agentId} (tx: ${relay.txHash})`);
|
|
1923
|
-
break;
|
|
1924
|
-
}
|
|
1925
|
-
// ── Teaching Exchanges ──
|
|
1926
|
-
case "propose_teaching": {
|
|
1927
|
-
const learnerAddress = action.learnerAddress;
|
|
1928
|
-
const goal = (action.goal ?? action.suggestedContent);
|
|
1929
|
-
const offerings = action.offerings;
|
|
1930
|
-
if (!learnerAddress || !goal || !offerings?.length)
|
|
1931
|
-
throw new Error("propose_teaching requires learnerAddress, goal, offerings[]");
|
|
1932
|
-
await runtime.connection.request("POST", "/v1/teaching/propose", { learnerAddress, goal, offerings });
|
|
1933
|
-
break;
|
|
1934
|
-
}
|
|
1935
|
-
case "accept_teaching": {
|
|
1936
|
-
const exchangeId = action.exchangeId;
|
|
1937
|
-
if (!exchangeId)
|
|
1938
|
-
throw new Error("accept_teaching requires exchangeId");
|
|
1939
|
-
await runtime.connection.request("POST", `/v1/teaching/${exchangeId}/accept`, {});
|
|
1940
|
-
break;
|
|
1941
|
-
}
|
|
1942
|
-
case "deliver_teaching": {
|
|
1943
|
-
const exchangeId = action.exchangeId;
|
|
1944
|
-
if (!exchangeId)
|
|
1945
|
-
throw new Error("deliver_teaching requires exchangeId");
|
|
1946
|
-
await runtime.connection.request("POST", `/v1/teaching/${exchangeId}/deliver`, { notes: action.notes });
|
|
1947
|
-
break;
|
|
1948
|
-
}
|
|
1949
|
-
case "approve_teaching": {
|
|
1950
|
-
const exchangeId = action.exchangeId;
|
|
1951
|
-
if (!exchangeId)
|
|
1952
|
-
throw new Error("approve_teaching requires exchangeId");
|
|
1953
|
-
await runtime.connection.request("POST", `/v1/teaching/${exchangeId}/approve`, { feedback: action.feedback, rating: action.rating });
|
|
1954
|
-
break;
|
|
1955
|
-
}
|
|
1956
|
-
case "reject_teaching": {
|
|
1957
|
-
const exchangeId = action.exchangeId;
|
|
1958
|
-
if (!exchangeId)
|
|
1959
|
-
throw new Error("reject_teaching requires exchangeId");
|
|
1960
|
-
await runtime.connection.request("POST", `/v1/teaching/${exchangeId}/reject`, { feedback: action.feedback });
|
|
1961
|
-
break;
|
|
1962
|
-
}
|
|
1963
|
-
case "search_teachers": {
|
|
1964
|
-
const goal = (action.goal ?? action.query);
|
|
1965
|
-
if (!goal)
|
|
1966
|
-
throw new Error("search_teachers requires goal");
|
|
1967
|
-
await runtime.connection.request("GET", `/v1/teaching/search-teachers?goal=${encodeURIComponent(goal)}&limit=${action.limit || 10}`);
|
|
1968
|
-
break;
|
|
1969
|
-
}
|
|
1970
|
-
// ── Credit Hire (off-chain marketplace) ──
|
|
1971
|
-
case "credit_hire": {
|
|
1972
|
-
const listingId = action.listingId;
|
|
1973
|
-
const terms = (action.terms ?? action.suggestedContent);
|
|
1974
|
-
const creditAmount = action.creditAmount;
|
|
1975
|
-
if (!listingId || !terms || !creditAmount)
|
|
1976
|
-
throw new Error("credit_hire requires listingId, terms, creditAmount");
|
|
1977
|
-
await runtime.connection.request("POST", "/v1/marketplace/credit-hire", { listingId, terms, creditAmount });
|
|
1978
|
-
break;
|
|
1979
|
-
}
|
|
1980
|
-
case "accept_credit_agreement": {
|
|
1981
|
-
const agreementId = action.agreementId;
|
|
1982
|
-
if (!agreementId)
|
|
1983
|
-
throw new Error("accept_credit_agreement requires agreementId");
|
|
1984
|
-
await runtime.connection.request("POST", `/v1/marketplace/credit-agreements/${agreementId}/accept`, {});
|
|
1985
|
-
break;
|
|
1986
|
-
}
|
|
1987
|
-
case "deliver_credit_work": {
|
|
1988
|
-
const agreementId = action.agreementId;
|
|
1989
|
-
if (!agreementId)
|
|
1990
|
-
throw new Error("deliver_credit_work requires agreementId");
|
|
1991
|
-
await runtime.connection.request("POST", `/v1/marketplace/credit-agreements/${agreementId}/deliver`, { deliveryNotes: action.deliveryNotes });
|
|
1992
|
-
break;
|
|
1993
|
-
}
|
|
1994
|
-
case "complete_credit_agreement": {
|
|
1995
|
-
const agreementId = action.agreementId;
|
|
1996
|
-
if (!agreementId)
|
|
1997
|
-
throw new Error("complete_credit_agreement requires agreementId");
|
|
1998
|
-
await runtime.connection.request("POST", `/v1/marketplace/credit-agreements/${agreementId}/complete`, { rating: action.rating, review: action.review });
|
|
1999
|
-
break;
|
|
2000
|
-
}
|
|
2001
|
-
case "cancel_credit_agreement": {
|
|
2002
|
-
const agreementId = action.agreementId;
|
|
2003
|
-
if (!agreementId)
|
|
2004
|
-
throw new Error("cancel_credit_agreement requires agreementId");
|
|
2005
|
-
await runtime.connection.request("POST", `/v1/marketplace/credit-agreements/${agreementId}/cancel`, {});
|
|
2006
|
-
break;
|
|
2007
|
-
}
|
|
2008
|
-
// GPU marketplace actions
|
|
2009
|
-
case "gpu_search": {
|
|
2010
|
-
const result = await runtime.gpu.searchAvailable({
|
|
2011
|
-
gpuModel: action.gpuModel,
|
|
2012
|
-
minVram: action.minVram,
|
|
2013
|
-
status: action.status,
|
|
2014
|
-
limit: action.limit || 10,
|
|
2015
|
-
});
|
|
2016
|
-
log(`[reactive] GPU search completed: ${JSON.stringify(result)}`);
|
|
2017
|
-
break;
|
|
2018
|
-
}
|
|
2019
|
-
case "gpu_heartbeat": {
|
|
2020
|
-
const listingId = Number(action.listingId);
|
|
2021
|
-
if (!listingId)
|
|
2022
|
-
throw new Error("gpu_heartbeat requires listingId");
|
|
2023
|
-
await runtime.gpu.heartbeat({
|
|
2024
|
-
listingId,
|
|
2025
|
-
status: action.status || "idle",
|
|
2026
|
-
gpuModel: action.gpuModel,
|
|
2027
|
-
vramGb: action.vramGb,
|
|
2028
|
-
gpuTempC: action.gpuTempC,
|
|
2029
|
-
gpuUtilization: action.gpuUtilization,
|
|
2030
|
-
vramUsedGb: action.vramUsedGb,
|
|
2031
|
-
});
|
|
2032
|
-
log(`[reactive] GPU heartbeat sent for listing ${listingId}`);
|
|
2033
|
-
break;
|
|
2034
|
-
}
|
|
2035
|
-
case "gpu_challenge": {
|
|
2036
|
-
const listingId = Number(action.listingId);
|
|
2037
|
-
const providerAddress = (action.providerAddress || target);
|
|
2038
|
-
const challengeInputCid = action.challengeInputCid;
|
|
2039
|
-
if (!listingId || !providerAddress || !challengeInputCid)
|
|
2040
|
-
throw new Error("gpu_challenge requires listingId, providerAddress, challengeInputCid");
|
|
2041
|
-
await runtime.gpu.createChallenge({
|
|
2042
|
-
listingId,
|
|
2043
|
-
providerAddress,
|
|
2044
|
-
challengeInputCid,
|
|
2045
|
-
expectedMinTflops: action.expectedMinTflops,
|
|
2046
|
-
});
|
|
2047
|
-
log(`[reactive] GPU challenge created for listing ${listingId}`);
|
|
2048
|
-
break;
|
|
2049
|
-
}
|
|
2050
|
-
case "gpu_submit_challenge": {
|
|
2051
|
-
const challengeId = action.challengeId;
|
|
2052
|
-
const challengeOutputCid = action.challengeOutputCid;
|
|
2053
|
-
if (!challengeId || !challengeOutputCid)
|
|
2054
|
-
throw new Error("gpu_submit_challenge requires challengeId, challengeOutputCid");
|
|
2055
|
-
await runtime.gpu.submitChallengeResult({
|
|
2056
|
-
challengeId,
|
|
2057
|
-
challengeOutputCid,
|
|
2058
|
-
actualTflops: action.actualTflops,
|
|
2059
|
-
wallTimeMs: action.wallTimeMs,
|
|
2060
|
-
});
|
|
2061
|
-
log(`[reactive] GPU challenge result submitted for ${challengeId}`);
|
|
2062
|
-
break;
|
|
2063
|
-
}
|
|
2064
|
-
case "gpu_submit_attestation": {
|
|
2065
|
-
const benchmarkHash = action.benchmarkHash;
|
|
2066
|
-
const gpuModel = action.gpuModel;
|
|
2067
|
-
const vramGb = action.vramGb;
|
|
2068
|
-
if (!benchmarkHash || !gpuModel || !vramGb)
|
|
2069
|
-
throw new Error("gpu_submit_attestation requires benchmarkHash, gpuModel, vramGb");
|
|
2070
|
-
const result = await runtime.gpu.submitAttestation({
|
|
2071
|
-
benchmarkHash,
|
|
2072
|
-
gpuModel,
|
|
2073
|
-
vramGb,
|
|
2074
|
-
computeCapability: action.computeCapability,
|
|
2075
|
-
cudaVersion: action.cudaVersion,
|
|
2076
|
-
});
|
|
2077
|
-
log(`[reactive] GPU attestation submitted (tx: ${result.txHash})`);
|
|
2078
|
-
break;
|
|
2079
|
-
}
|
|
2080
|
-
case "gpu_update_attestation": {
|
|
2081
|
-
const benchmarkHash = action.benchmarkHash;
|
|
2082
|
-
if (!benchmarkHash)
|
|
2083
|
-
throw new Error("gpu_update_attestation requires benchmarkHash");
|
|
2084
|
-
const result = await runtime.gpu.updateAttestation(benchmarkHash);
|
|
2085
|
-
log(`[reactive] GPU attestation updated (tx: ${result.txHash})`);
|
|
2086
|
-
break;
|
|
2087
|
-
}
|
|
2088
|
-
case "gpu_revoke_attestation": {
|
|
2089
|
-
const result = await runtime.gpu.revokeAttestation();
|
|
2090
|
-
log(`[reactive] GPU attestation revoked (tx: ${result.txHash})`);
|
|
2091
|
-
break;
|
|
2092
|
-
}
|
|
2093
|
-
case "ignore":
|
|
2094
|
-
break;
|
|
2095
|
-
default: {
|
|
2096
|
-
// ── MCP fallback ──────────────────────────────────────────
|
|
2097
|
-
// Any action not explicitly handled above gets routed through
|
|
2098
|
-
// the MCP tool bridge. Maps action_name → nookplot_action_name
|
|
2099
|
-
// and calls the gateway's MCP server. This gives CLI agents
|
|
2100
|
-
// access to all 197 MCP tools without a dedicated switch case.
|
|
2101
|
-
const mcpName = `nookplot_${action.action}`;
|
|
2102
|
-
// Build args from all action fields except "action" itself
|
|
2103
|
-
const mcpArgs = {};
|
|
2104
|
-
for (const [k, v] of Object.entries(action)) {
|
|
2105
|
-
if (k !== "action" && v !== undefined)
|
|
2106
|
-
mcpArgs[k] = v;
|
|
2107
|
-
}
|
|
2108
|
-
try {
|
|
2109
|
-
const mcpResult = await runtime.tools.executeTool(mcpName, mcpArgs);
|
|
2110
|
-
log(`[reactive] MCP fallback: ${mcpName} → ok`);
|
|
2111
|
-
}
|
|
2112
|
-
catch (mcpErr) {
|
|
2113
|
-
log(`[reactive] MCP fallback failed for ${mcpName}: ${mcpErr instanceof Error ? mcpErr.message : String(mcpErr)}`);
|
|
2114
|
-
}
|
|
2115
|
-
break;
|
|
2116
|
-
}
|
|
616
|
+
// ── Unified dispatch via POST /v1/actions/execute ──
|
|
617
|
+
// The gateway's ToolDispatcher routes the call to the correct internal
|
|
618
|
+
// endpoint, replacing the 2000+ line switch statement that was here before.
|
|
619
|
+
if (action.action === "ignore") {
|
|
620
|
+
return;
|
|
621
|
+
}
|
|
622
|
+
const toolName = `nookplot_${action.action}`;
|
|
623
|
+
const payload = { ...action };
|
|
624
|
+
delete payload.action; // toolName carries the action type
|
|
625
|
+
// Merge signal context (senderAddress, channelId) into payload
|
|
626
|
+
if (target && !payload.to)
|
|
627
|
+
payload.to = target;
|
|
628
|
+
if (content && !payload.content)
|
|
629
|
+
payload.content = content;
|
|
630
|
+
if (channelId && !payload.channelId)
|
|
631
|
+
payload.channelId = channelId;
|
|
632
|
+
const dispatchResult = await runtime.connection.request("POST", "/v1/actions/execute", { toolName, payload });
|
|
633
|
+
switch (dispatchResult.status) {
|
|
634
|
+
case "completed":
|
|
635
|
+
break;
|
|
636
|
+
case "sign_required": {
|
|
637
|
+
// On-chain action: sign locally + relay
|
|
638
|
+
if (!dispatchResult.forwardRequest || !dispatchResult.domain || !dispatchResult.types) {
|
|
639
|
+
throw new Error(`sign_required response missing forwardRequest/domain/types for ${action.action}`);
|
|
640
|
+
}
|
|
641
|
+
const { signForwardRequest } = await import("@nookplot/runtime");
|
|
642
|
+
const privateKey = runtime.connection.privateKey;
|
|
643
|
+
if (!privateKey)
|
|
644
|
+
throw new Error("Private key not configured — cannot sign on-chain transactions.");
|
|
645
|
+
const signature = await signForwardRequest(privateKey, dispatchResult.domain, dispatchResult.types, dispatchResult.forwardRequest);
|
|
646
|
+
const relayResult = await runtime.connection.request("POST", "/v1/relay", { ...dispatchResult.forwardRequest, signature });
|
|
647
|
+
log(`[reactive] On-chain tx: ${relayResult.txHash}`);
|
|
648
|
+
break;
|
|
649
|
+
}
|
|
650
|
+
case "client_side_required":
|
|
651
|
+
log(`[reactive] Client-side action required: ${dispatchResult.action}`);
|
|
652
|
+
break;
|
|
653
|
+
case "error":
|
|
654
|
+
throw new Error(dispatchResult.error ?? `Action failed: ${action.action}`);
|
|
655
|
+
default:
|
|
656
|
+
log(`[reactive] Unexpected dispatch status: ${dispatchResult.status}`);
|
|
2117
657
|
}
|
|
2118
658
|
if (action.action !== "ignore") {
|
|
2119
659
|
log(`[reactive] ${action.action}${target ? ` -> ${target.slice(0, 10)}...` : ""}`);
|