@nookplot/cli 0.6.80 → 0.6.82

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.
@@ -14,9 +14,8 @@
14
14
  import chalk from "chalk";
15
15
  import ora from "ora";
16
16
  import { spawn } from "node:child_process";
17
- import { NookplotRuntime, AutonomousAgent, prepareSignRelay, ACTION_CATALOG } from "@nookplot/runtime";
17
+ import { NookplotRuntime, AutonomousAgent, ACTION_CATALOG, getAvailableActionsFromMap, getCategoryListing, getToolsInCategory } from "@nookplot/runtime";
18
18
  import { loadConfig, validateConfig } from "../config.js";
19
- import { filterByProfile } from "../skillGenerator.js";
20
19
  // Valid event types from runtime/src/types.ts RuntimeEventType
21
20
  const VALID_EVENT_TYPES = new Set([
22
21
  "post.new",
@@ -413,2958 +412,77 @@ async function runListen(globalOpts, eventTypes, cmdOpts) {
413
412
  });
414
413
  }
415
414
  }
415
+ /** Session state: dynamically loaded tool categories via browse_tools. */
416
+ const loadedCategories = new Set();
416
417
  /**
417
418
  * Get available actions the agent can take in response to a signal type.
418
419
  * These are hints — the agent decides which (if any) to execute.
419
420
  */
420
421
  function getAvailableActions(signalType) {
421
- return filterByProfile(_getAvailableActionsRaw(signalType));
422
- }
423
- function _getAvailableActionsRaw(signalType) {
424
- switch (signalType) {
425
- case "dm_received":
426
- return [
427
- "reply", "send_dm", "follow_back", "attest_back", "propose_collab",
428
- "vote", "publish", "create_post", "create_bounty", "create_project",
429
- "create_community", "create_listing", "commit_files", "create_task",
430
- "link_project_to_guild", "propose_guild", "deploy_preview",
431
- "egress_request", "execute_tool", "exec_code", "call_mcp_tool", "register_webhook",
432
- "workspace_create", "publish_insight",
433
- "create_intent", "browse_intents",
434
- "launch_token", "preview_token_launch",
435
- "search_skills", "install_skill", "store_memory", "recall_memory",
436
- "propose_teaching", "search_teachers",
437
- "credit_hire",
438
- "ignore",
439
- ];
440
- case "channel_message":
441
- case "channel_mention":
442
- case "project_discussion":
443
- return [
444
- "reply", "publish", "vote", "follow", "attest", "propose_collab",
445
- "create_post", "create_bounty", "create_project", "commit_files",
446
- "create_task", "link_project_to_guild", "propose_guild",
447
- "egress_request", "execute_tool", "exec_code", "call_mcp_tool",
448
- "workspace_create", "publish_insight",
449
- "create_intent", "browse_intents",
450
- "search_skills", "install_skill", "store_memory",
451
- "ignore",
452
- ];
453
- case "new_follower":
454
- return ["follow_back", "send_dm", "ignore"];
455
- case "attestation_received":
456
- return ["attest_back", "endorse_agent", "send_dm", "ignore"];
457
- case "endorsement_received":
458
- return ["endorse_agent", "attest_back", "send_dm", "ignore"];
459
- case "files_committed":
460
- case "pending_review":
461
- return ["review", "comment", "request_ai_review", "list_project_files", "read_project_file", "list_commits", "get_commit_detail", "list_merge_requests", "get_merge_request", "ignore"];
462
- case "merge_request_created":
463
- return ["get_merge_request", "merge_merge_request", "close_merge_request", "reply", "ignore"];
464
- case "project_forked":
465
- return ["acknowledge", "send_dm", "ignore"];
466
- case "review_submitted":
467
- return ["reply", "ignore"];
468
- case "collaborator_added":
469
- return ["send_message", "reply", "ignore"];
470
- case "new_post_in_community":
471
- case "post_reply":
472
- case "reply_to_own_post":
473
- return ["reply", "post_reply", "vote", "publish", "ignore"];
474
- case "bounty":
475
- return ["claim", "apply_bounty", "create_bounty", "reply", "ignore"];
476
- case "community_gap":
477
- return ["create_community", "ignore"];
478
- case "potential_friend":
479
- return ["follow", "send_dm", "attest", "endorse_agent", "ignore"];
480
- case "attestation_opportunity":
481
- return ["attest", "endorse_agent", "send_dm", "ignore"];
482
- case "directive":
483
- return [
484
- "execute", "reply", "publish", "create_project", "commit_files",
485
- "create_task", "assign_task", "complete_task", "update_task",
486
- "link_project_to_guild", "propose_guild", "approve_guild", "reject_guild", "leave_guild",
487
- "create_bounty", "create_bundle", "propose_collab", "assemble_team",
488
- "find_agents", "deploy_preview", "add_collaborator",
489
- "fork_project", "create_merge_request", "list_merge_requests", "get_merge_request", "merge_merge_request", "close_merge_request",
490
- "create_listing", "create_agreement", "cancel_agreement",
491
- "workspace_create", "workspace_set", "workspace_snapshot",
492
- "propose_action", "vote_proposal", "cancel_proposal",
493
- "egress_request", "execute_tool", "exec_code", "call_mcp_tool", "connect_mcp_server", "disconnect_mcp_server", "register_webhook",
494
- "publish_insight", "cite_insight", "apply_insight",
495
- "deposit_treasury", "withdraw_treasury", "fund_bounty_from_treasury", "distribute_revenue",
496
- "create_swarm", "claim_subtask", "submit_swarm_result", "aggregate_swarm",
497
- "record_gap", "update_proficiency", "generate_recommendations",
498
- "create_intent", "browse_intents", "submit_proposal", "accept_proposal", "reject_proposal",
499
- "cancel_intent", "complete_intent", "withdraw_proposal", "query_oracle",
500
- "launch_token", "preview_token_launch", "claim_clawnch_fees", "get_token_analytics",
501
- "create_search_subscription",
502
- "send_email", "reply_email", "check_email", "create_email_inbox",
503
- "search_skills", "publish_skill", "install_skill", "review_skill", "update_skill", "trending_skills",
504
- "store_memory", "recall_memory", "list_memories", "memory_stats", "export_memories", "import_memories",
505
- "forge_deploy", "forge_spawn", "forge_update_soul",
506
- "propose_teaching", "accept_teaching", "deliver_teaching", "approve_teaching", "reject_teaching", "search_teachers",
507
- "credit_hire", "accept_credit_agreement", "deliver_credit_work", "complete_credit_agreement", "cancel_credit_agreement",
508
- "claim_reward",
509
- "endorse_agent", "revoke_endorsement",
510
- "block_agent", "unblock_agent",
511
- "list_project_files", "read_project_file", "list_commits", "get_commit_detail",
512
- "gpu_search", "gpu_heartbeat", "gpu_challenge", "gpu_submit_challenge",
513
- "gpu_submit_attestation", "gpu_update_attestation", "gpu_revoke_attestation",
514
- "gpu_rent",
515
- "ignore",
516
- ];
517
- case "collab_request":
518
- return ["add_collaborator", "propose_collab", "reply", "ignore"];
519
- case "team_assembly_suggested":
520
- return ["assemble_team", "ignore"];
521
- case "team_invitation":
522
- return ["accept_invitation", "decline_invitation", "ignore"];
523
- case "team_invitation_accepted":
524
- case "team_invitation_declined":
525
- return ["reply", "ignore"];
526
- case "service":
527
- return ["reply", "update_service", "create_listing", "create_agreement", "ignore"];
528
- case "time_to_post":
529
- return ["create_post", "create_bounty", "create_bundle", "publish_insight", "create_listing", "publish_skill", "ignore"];
530
- case "time_to_create_project":
531
- return ["create_project", "assemble_team", "ignore"];
532
- case "task_assigned":
533
- return ["accept", "update_task", "complete_task", "assign_task", "assemble_team", "reply", "ignore"];
534
- case "task_completed":
535
- return ["reply", "review", "create_task", "ignore"];
536
- case "milestone_reached":
537
- return ["reply", "ignore"];
538
- case "review_comment_added":
539
- return ["reply", "ignore"];
540
- case "agent_mentioned":
541
- return ["reply", "acknowledge", "ignore"];
542
- case "project_status_update":
543
- return ["reply", "ignore"];
544
- case "file_shared":
545
- return ["reply", "ignore"];
546
- case "bounty_posted_to_project":
547
- return ["reply", "claim", "ignore"];
548
- case "bounty_access_requested":
549
- return ["grant", "deny", "ignore"];
550
- case "bounty_access_granted":
551
- return ["reply", "claim", "ignore"];
552
- case "project_bounty_claimed":
553
- return ["reply", "ignore"];
554
- case "project_bounty_completed":
555
- return ["reply", "ignore"];
556
- case "xmtp_message":
557
- return ["reply", "ignore"];
558
- case "guild_opportunity":
559
- return ["join_guild", "approve_guild", "reject_guild", "leave_guild", "propose_guild", "link_project_to_guild", "reply", "ignore"];
560
- // Marketplace signals
561
- case "agreement_created":
562
- return ["deliver_work", "cancel_agreement", "send_agreement_message", "ignore"];
563
- case "work_delivered":
564
- return ["settle_agreement", "dispute_agreement", "send_agreement_message", "expire_delivered", "ignore"];
565
- case "agreement_settled":
566
- return ["submit_review", "ignore"];
567
- case "agreement_disputed":
568
- return ["send_agreement_message", "expire_dispute", "ignore"];
569
- case "agreement_cancelled":
570
- return ["ignore"];
571
- case "revision_requested":
572
- return ["deliver_work", "send_agreement_message", "ignore"];
573
- case "review_received":
574
- return ["ignore"];
575
- // Bounty application/submission signals
576
- case "bounty_application_submitted":
577
- return ["approve_bounty_claimer", "reject_bounty_application", "ignore"];
578
- case "bounty_application_approved":
579
- return ["claim_bounty", "ignore"];
580
- case "bounty_application_rejected":
581
- return ["ignore"];
582
- case "bounty_work_submitted":
583
- return ["select_bounty_submission", "ignore"];
584
- case "bounty_submission_selected":
585
- return ["claim_bounty", "ignore"];
586
- case "bounty_submission_not_selected":
587
- return ["ignore"];
588
- // On-chain bounty lifecycle signals
589
- case "bounty_claimed":
590
- return ["approve_bounty_work", "approve_bounty_claimer", "dispute_bounty_work", "unclaim_bounty", "ignore"];
591
- case "bounty_work_approved":
592
- return ["ignore"];
593
- case "bounty_disputed":
594
- return ["cancel_bounty", "ignore"];
595
- case "bounty_cancelled":
596
- return ["ignore"];
597
- case "bounty_claimer_approved":
598
- return ["claim_bounty", "ignore"];
599
- case "intent_matched":
600
- return ["submit_proposal", "browse_intents", "reply", "ignore"];
601
- case "proposal_received":
602
- return ["accept_proposal", "reject_proposal", "reply", "ignore"];
603
- case "intent_accepted":
604
- return ["complete_intent", "reply", "ignore"];
605
- case "email_received":
606
- return ["reply_email", "send_email", "send_dm", "ignore"];
607
- case "specialization_path":
608
- return ["reply", "record_gap", "update_proficiency", "search_skills", "install_skill", "store_memory", "ignore"];
609
- // Teaching signals
610
- case "teaching_proposed":
611
- return ["accept_teaching", "reject_teaching", "reply", "ignore"];
612
- case "teaching_accepted":
613
- return ["deliver_teaching", "reply", "ignore"];
614
- case "teaching_delivered":
615
- return ["approve_teaching", "reject_teaching", "reply", "ignore"];
616
- case "teaching_opportunity":
617
- return ["propose_teaching", "search_teachers", "reply", "ignore"];
618
- // Credit agreement signals
619
- case "credit_agreement_created":
620
- return ["accept_credit_agreement", "cancel_credit_agreement", "reply", "ignore"];
621
- case "credit_work_delivered":
622
- return ["complete_credit_agreement", "cancel_credit_agreement", "reply", "ignore"];
623
- case "credit_agreement_accepted":
624
- return ["deliver_credit_work", "cancel_credit_agreement", "reply", "ignore"];
625
- // Informational signals
626
- case "new_project":
627
- case "interesting_project":
628
- return ["propose_collab", "reply", "ignore"];
629
- case "bounty_access_denied":
630
- return ["ignore"];
631
- case "task_created":
632
- case "task_deleted":
633
- case "status_updated":
634
- return ["reply", "ignore"];
635
- case "welcome_guide":
636
- return ["reply", "create_post", "ignore"];
637
- case "onboarding_suggestion":
638
- return ["reply", "ignore"];
639
- case "new_bundle_in_domain":
640
- return ["cite_insight", "reply", "ignore"];
641
- case "bundle_cited":
642
- return ["ignore"];
643
- case "webhook_received":
644
- case "webhook.received":
645
- return ["reply", "egress_request", "execute_tool", "ignore"];
646
- case "bounty_opportunity":
647
- return ["apply_bounty", "send_dm", "reply", "ignore"];
648
- default:
649
- return ["reply", "ignore"];
650
- }
422
+ return getAvailableActionsFromMap(signalType, loadedCategories);
651
423
  }
652
424
  /**
653
425
  * Execute an action the agent decided to take in response to a trigger.
654
426
  * The agent returns a JSON object with { action, ... } and we route it.
655
427
  */
656
- /** Validate an ID before URL interpolation — must be numeric or UUID. */
657
- function validateId(id, name) {
658
- const s = String(id ?? "");
659
- 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))
660
- return s;
661
- throw new Error(`Invalid ${name}: ${s}`);
662
- }
663
428
  async function executeAgentAction(runtime, action, signal, json) {
664
429
  const target = action.to || signal.senderAddress || "";
665
430
  const content = action.content || "";
666
431
  const channelId = action.channelId || signal.channelId || "";
667
432
  try {
668
- let result; // eslint-disable-line @typescript-eslint/no-unused-vars
669
- switch (action.action) {
670
- case "reply":
671
- if (channelId) {
672
- await runtime.channels.send(channelId, content);
673
- }
674
- else if (target) {
675
- await runtime.inbox.send({ to: target, content });
676
- }
677
- break;
678
- case "send_dm":
679
- if (target)
680
- await runtime.inbox.send({ to: target, content });
681
- break;
682
- case "follow_agent":
683
- case "follow_back":
684
- case "follow":
685
- if (target)
686
- await runtime.social.follow(target);
687
- break;
688
- case "attest_agent":
689
- case "attest_back":
690
- case "attest":
691
- if (target)
692
- await runtime.social.attest(target, action.reason || "Valued collaborator");
693
- break;
694
- case "endorse_agent":
695
- case "endorse":
696
- if (target && action.skill) {
697
- await runtime.social.endorse(target, action.skill, Number(action.rating ?? 3), action.context || "");
698
- }
699
- break;
700
- case "revoke_endorsement":
701
- if (target && action.skill) {
702
- await runtime.social.revokeEndorsement(target, action.skill);
703
- }
704
- break;
705
- case "block_agent":
706
- if (target) {
707
- await runtime.social.block(target);
708
- }
709
- break;
710
- case "unblock_agent":
711
- if (target) {
712
- await runtime.social.unblock(target);
713
- }
714
- break;
715
- case "vote":
716
- if (action.cid) {
717
- await runtime.memory.vote({ cid: action.cid, type: (action.voteType || "up") });
718
- }
719
- break;
720
- case "review_commit":
721
- case "review":
722
- case "comment": {
723
- const projectId = (action.projectId || signal.projectId);
724
- const commitId = (action.commitId || signal.commitId);
725
- const verdict = action.action === "comment" ? "comment" : action.verdict || "comment";
726
- const body = content || "Reviewed";
727
- if (projectId && commitId) {
728
- await runtime.projects.submitReview(projectId, commitId, verdict, body);
729
- }
730
- break;
731
- }
732
- case "request_ai_review": {
733
- // AI-powered code review — costs 150 credits (1.50 cr).
734
- // Requires the project to have a linked GitHub repo.
735
- const projId2 = (action.projectId || signal.projectId);
736
- const commitId2 = (action.commitId || signal.commitId);
737
- if (projId2 && commitId2) {
738
- const aiResult = await runtime.projects.requestAIReview(projId2, commitId2);
739
- if (!json)
740
- console.log(chalk.dim(` [reactive] AI review: ${aiResult.verdict} — ${aiResult.findingsCount} finding(s), cost ${aiResult.creditsCost} credits`));
741
- }
742
- break;
743
- }
744
- case "send_message":
745
- if (target) {
746
- await runtime.inbox.send({ to: target, content: content || "Hey! Looking forward to collaborating." });
747
- }
748
- else if (channelId) {
749
- await runtime.channels.send(channelId, content || "Hey everyone! Excited to join.");
750
- }
751
- break;
752
- case "apply_bounty": {
753
- const bountyId = validateId(action.bountyId || signal.bountyId, "bountyId");
754
- const applyMsg = action.message || content || "";
755
- if (!applyMsg || applyMsg.length < 50)
756
- throw new Error("apply_bounty requires a work submission (minimum 50 characters)");
757
- await runtime.connection.request("POST", `/v1/bounties/${bountyId}/apply`, { message: applyMsg });
758
- if (!json)
759
- console.log(chalk.dim(` [reactive] Applied to bounty: ${bountyId}`));
760
- break;
761
- }
762
- case "submit_bounty_work": {
763
- const bountyId = validateId(action.bountyId || signal.bountyId, "bountyId");
764
- const workContent = content || action.workContent || "";
765
- const cids = action.deliverableCids || [];
766
- const projectId = action.projectId;
767
- const commitIds = action.commitIds || [];
768
- await runtime.connection.request("POST", `/v1/bounties/${bountyId}/submissions`, {
769
- content: workContent,
770
- deliverableCids: cids,
771
- ...(projectId ? { projectId } : {}),
772
- ...(commitIds.length > 0 ? { commitIds } : {}),
773
- });
774
- if (!json)
775
- console.log(chalk.dim(` [reactive] Work submitted for bounty: ${bountyId}`));
776
- break;
777
- }
778
- case "claim":
779
- case "claim_bounty": {
780
- const rawBountyId = action.bountyId || signal.bountyId;
781
- if (rawBountyId) {
782
- const bountyId = validateId(rawBountyId, "bountyId");
783
- const result = await prepareSignRelay(runtime.connection, `/v1/prepare/bounty/${bountyId}/claim`, {});
784
- if (!json)
785
- console.log(chalk.dim(` [reactive] Bounty claimed: ${bountyId} (tx: ${result.txHash})`));
786
- }
787
- else {
788
- if (!json)
789
- console.log(chalk.dim(` [reactive] Bounty claim requested but no bountyId provided`));
790
- }
791
- break;
792
- }
793
- case "approve_bounty_claimer": {
794
- const rawBountyId = action.bountyId || signal.bountyId;
795
- const claimer = action.claimer;
796
- if (rawBountyId && claimer) {
797
- const bountyId = validateId(rawBountyId, "bountyId");
798
- const result = await prepareSignRelay(runtime.connection, `/v1/prepare/bounty/${bountyId}/approve-claimer`, { claimer });
799
- if (!json)
800
- console.log(chalk.dim(` [reactive] Bounty claimer approved: ${bountyId} → ${claimer} (tx: ${result.txHash})`));
801
- }
802
- else {
803
- if (!json)
804
- console.log(chalk.dim(` [reactive] approve_bounty_claimer requires bountyId and claimer`));
805
- }
806
- break;
807
- }
808
- case "approve_bounty_application": {
809
- const bountyId = validateId(action.bountyId || signal.bountyId, "bountyId");
810
- const applicationId = validateId(action.applicationId, "applicationId");
811
- await runtime.connection.request("POST", `/v1/bounties/${bountyId}/applications/${applicationId}/approve`, {});
812
- if (!json)
813
- console.log(chalk.dim(` [reactive] Approved bounty application: ${applicationId} on bounty ${bountyId}`));
814
- break;
815
- }
816
- case "reject_bounty_application": {
817
- const bountyId = validateId(action.bountyId || signal.bountyId, "bountyId");
818
- const applicationId = validateId(action.applicationId, "applicationId");
819
- await runtime.connection.request("POST", `/v1/bounties/${bountyId}/applications/${applicationId}/reject`, {});
820
- if (!json)
821
- console.log(chalk.dim(` [reactive] Rejected bounty application: ${applicationId} on bounty ${bountyId}`));
822
- break;
823
- }
824
- case "select_bounty_submission": {
825
- const bountyId = validateId(action.bountyId || signal.bountyId, "bountyId");
826
- const submissionId = validateId(action.submissionId, "submissionId");
827
- const selectResult = await runtime.connection.request("POST", `/v1/bounties/${bountyId}/submissions/${submissionId}/select`, {});
828
- if (!json)
829
- console.log(chalk.dim(` [reactive] Selected bounty submission: ${submissionId} on bounty ${bountyId}`));
830
- // Bridge: approve winner on-chain so they can claim
831
- try {
832
- const winnerAddress = selectResult?.winner?.applicantAddress;
833
- if (winnerAddress) {
834
- const relay = await prepareSignRelay(runtime.connection, `/v1/prepare/bounty/${bountyId}/approve-claimer`, { claimer: winnerAddress });
835
- if (!json)
836
- console.log(chalk.dim(` [reactive] Approved claimer on-chain: ${bountyId} → ${winnerAddress} (tx: ${relay.txHash})`));
837
- }
838
- }
839
- catch { /* non-fatal */ }
840
- break;
841
- }
842
- case "create_community": {
843
- const slug = action.slug;
844
- const name = action.name || content;
845
- const desc = action.description || content || "";
846
- if (slug && name) {
847
- await prepareSignRelay(runtime.connection, "/v1/prepare/community", { slug, name, description: desc });
848
- }
849
- break;
850
- }
851
- case "create_project": {
852
- const projName = action.name || content;
853
- const projDesc = action.description || "";
854
- const projId = action.projectId || projName?.toLowerCase().replace(/\s+/g, "-");
855
- if (projId && projName) {
856
- // Discover similar projects first (gateway requires discoveryId)
857
- const discovery = await runtime.connection.request("POST", "/v1/projects/discover", { name: projName, description: projDesc });
858
- await prepareSignRelay(runtime.connection, "/v1/prepare/project", {
859
- discoveryId: discovery.discoveryId,
860
- projectId: projId, name: projName, description: projDesc,
861
- });
862
- }
863
- break;
864
- }
865
- case "commit_files":
866
- case "gateway_commit": {
867
- const projId = (action.projectId || signal.projectId);
868
- const files = action.files;
869
- const msg = content || "Automated commit";
870
- if (projId && files?.length) {
871
- await runtime.projects.commitFiles(projId, files, msg);
872
- }
873
- break;
874
- }
875
- case "list_project_files": {
876
- const projId = (action.projectId || signal.projectId);
877
- if (projId) {
878
- await runtime.projects.listFiles(projId);
879
- }
880
- break;
881
- }
882
- case "read_project_file": {
883
- const projId = (action.projectId || signal.projectId);
884
- const filePath = action.filePath;
885
- if (projId && filePath) {
886
- await runtime.projects.readFile(projId, filePath);
887
- }
888
- break;
889
- }
890
- case "list_commits": {
891
- const projId = (action.projectId || signal.projectId);
892
- if (projId) {
893
- const limit = action.limit ?? 20;
894
- const offset = action.offset ?? 0;
895
- await runtime.projects.listCommits(projId, limit, offset);
896
- }
897
- break;
898
- }
899
- case "get_commit_detail": {
900
- const projId = (action.projectId || signal.projectId);
901
- const commitId = action.commitId;
902
- if (projId && commitId) {
903
- await runtime.projects.getCommit(projId, commitId);
904
- }
905
- break;
906
- }
907
- case "add_collaborator": {
908
- const projId = (action.projectId || signal.projectId);
909
- const collabAddr = (action.collaboratorAddress || target);
910
- const role = action.role || "editor";
911
- if (projId && collabAddr) {
912
- await runtime.projects.addCollaborator(projId, collabAddr, role);
913
- }
914
- break;
915
- }
916
- case "link_project_to_guild":
917
- case "link_project_to_clique": {
918
- const projId2 = (action.projectId || signal.projectId);
919
- const gId = (action.guildId || action.cliqueId);
920
- if (projId2 && gId != null) {
921
- // 1. Link project to guild
922
- await runtime.guilds.linkProject(Number(gId), projId2);
923
- // 2. Set guild attribution
924
- await runtime.projects.setGuildAttribution(projId2, String(gId));
925
- // 3. Add accepted guild members as editors
926
- // Gateway returns members as [{address, status}] objects where status=2 = accepted
927
- const guild = await runtime.guilds.get(Number(gId));
928
- const rawMembers = (guild?.members ?? []);
929
- const myAddr = runtime.connection.address?.toLowerCase();
930
- for (const m of rawMembers) {
931
- if (typeof m === "string")
932
- continue; // bare string — can't confirm accepted
933
- if (m.status === 2 && m.address?.toLowerCase() !== myAddr) {
934
- try {
935
- await runtime.projects.addCollaborator(projId2, m.address, "editor");
936
- }
937
- catch { /* best-effort */ }
938
- }
939
- }
940
- }
941
- break;
942
- }
943
- case "propose_guild":
944
- case "propose_clique": {
945
- const guildName = action.name || content;
946
- const guildMembers2 = action.members;
947
- const guildDesc = action.description || "";
948
- if (guildName && guildMembers2 && guildMembers2.length >= 2) {
949
- const relay = await prepareSignRelay(runtime.connection, "/v1/prepare/guild", { name: guildName, description: guildDesc, members: guildMembers2 });
950
- if (!json)
951
- console.log(chalk.green(` [reactive] Proposed guild "${guildName}" (tx: ${relay.txHash})`));
952
- }
953
- break;
954
- }
955
- case "join_guild":
956
- case "approve_guild": {
957
- const gId = action.guildId;
958
- if (gId) {
959
- const relay = await prepareSignRelay(runtime.connection, `/v1/prepare/guild/${gId}/approve`, {});
960
- if (!json)
961
- console.log(chalk.green(` [reactive] Approved guild #${gId} membership (tx: ${relay.txHash})`));
962
- }
963
- break;
964
- }
965
- case "reject_guild": {
966
- const gId = action.guildId;
967
- if (gId) {
968
- const relay = await prepareSignRelay(runtime.connection, `/v1/prepare/guild/${gId}/reject`, {});
969
- if (!json)
970
- console.log(chalk.green(` [reactive] Rejected guild #${gId} membership (tx: ${relay.txHash})`));
971
- }
972
- break;
973
- }
974
- case "leave_guild": {
975
- const gId = action.guildId;
976
- if (gId) {
977
- const relay = await prepareSignRelay(runtime.connection, `/v1/prepare/guild/${gId}/leave`, {});
978
- if (!json)
979
- console.log(chalk.green(` [reactive] Left guild #${gId} (tx: ${relay.txHash})`));
980
- }
981
- break;
982
- }
983
- case "publish":
984
- case "create_post": {
985
- const community = action.community || "general";
986
- const title = action.title || content?.slice(0, 100) || "Untitled";
987
- const body = content || "";
988
- if (body) {
989
- await runtime.memory.publishKnowledge({ title, body, community });
990
- }
991
- break;
992
- }
993
- case "execute":
994
- if (channelId && content) {
995
- await runtime.channels.send(channelId, content);
996
- }
997
- else if (target && content) {
998
- await runtime.inbox.send({ to: target, content });
999
- }
1000
- break;
1001
- case "accept": {
1002
- const ch = action.channelId || signal.channelId || "";
1003
- const msg = content || "Accepted — I'll get started.";
1004
- if (ch)
1005
- await runtime.channels.send(ch, msg);
1006
- break;
1007
- }
1008
- case "acknowledge": {
1009
- const ch = action.channelId || signal.channelId || "";
1010
- const msg = content || "Got it, thanks for the mention!";
1011
- if (ch)
1012
- await runtime.channels.send(ch, msg);
1013
- break;
1014
- }
1015
- case "deploy_preview": {
1016
- const projId = (action.projectId || signal.projectId);
1017
- if (projId) {
1018
- const relay = await prepareSignRelay(runtime.connection, `/v1/prepare/project/${projId}/deployment`, { prepaidHours: action.prepaidHours ?? 2 });
1019
- if (!json)
1020
- console.log(chalk.green(` [reactive] Deploy preview for ${projId} (tx: ${relay.txHash})`));
1021
- }
1022
- break;
1023
- }
1024
- case "fork_project": {
1025
- const projId = (action.projectId || signal.projectId);
1026
- if (projId) {
1027
- const res = await runtime.projects.forkProject(projId, {
1028
- name: action.name,
1029
- });
1030
- if (!json)
1031
- console.log(chalk.green(` [reactive] Forked project ${projId} → ${res.projectId}`));
1032
- }
1033
- break;
1034
- }
1035
- case "create_merge_request": {
1036
- const srcId = (action.sourceProjectId || signal.projectId);
1037
- const tgtId = action.targetProjectId;
1038
- const mrTitle = action.title;
1039
- const commitIds = action.commitIds;
1040
- if (srcId && tgtId && mrTitle && commitIds?.length) {
1041
- const mr = await runtime.projects.createMergeRequest(srcId, tgtId, mrTitle, commitIds, action.description);
1042
- if (!json)
1043
- console.log(chalk.green(` [reactive] Created merge request "${mrTitle}" (${mr.id})`));
1044
- }
1045
- break;
1046
- }
1047
- case "list_merge_requests": {
1048
- const projId = (action.projectId || signal.projectId);
1049
- if (projId) {
1050
- const res = await runtime.projects.listMergeRequests(projId, {
1051
- status: action.status,
1052
- });
1053
- if (!json)
1054
- console.log(chalk.green(` [reactive] Listed ${res.mergeRequests.length} merge requests on ${projId}`));
1055
- }
1056
- break;
1057
- }
1058
- case "get_merge_request": {
1059
- const projId = (action.projectId || signal.projectId);
1060
- const mrId = action.mrId;
1061
- if (projId && mrId) {
1062
- const mr = await runtime.projects.getMergeRequest(projId, mrId);
1063
- if (!json)
1064
- console.log(chalk.green(` [reactive] Got merge request "${mr.title}" (${mr.status})`));
1065
- }
1066
- break;
1067
- }
1068
- case "merge_merge_request": {
1069
- const projId = (action.projectId || signal.projectId);
1070
- const mrId = action.mrId;
1071
- if (projId && mrId) {
1072
- await runtime.projects.mergeMergeRequest(projId, mrId, action.comment);
1073
- if (!json)
1074
- console.log(chalk.green(` [reactive] Merged MR ${mrId} into ${projId}`));
1075
- }
1076
- break;
1077
- }
1078
- case "close_merge_request": {
1079
- const projId = (action.projectId || signal.projectId);
1080
- const mrId = action.mrId;
1081
- if (projId && mrId) {
1082
- await runtime.projects.closeMergeRequest(projId, mrId, action.comment);
1083
- if (!json)
1084
- console.log(chalk.green(` [reactive] Closed MR ${mrId}`));
1085
- }
1086
- break;
1087
- }
1088
- case "claim_reward": {
1089
- const pool = action.pool || "nook";
1090
- const relay = await prepareSignRelay(runtime.connection, "/v1/prepare/reward/claim", { pool });
1091
- if (!json)
1092
- console.log(chalk.green(` [reactive] Reward claimed from ${pool} pool (tx: ${relay.txHash})`));
1093
- break;
1094
- }
1095
- case "create_task": {
1096
- const projId = (action.projectId || signal.projectId);
1097
- const title = (content || action.title);
1098
- if (projId && title) {
1099
- await runtime.connection.request("POST", `/v1/projects/${projId}/tasks`, {
1100
- title,
1101
- description: action.description,
1102
- milestoneId: action.milestoneId,
1103
- priority: action.priority ?? "medium",
1104
- labels: action.labels,
1105
- dueDate: action.dueDate,
1106
- });
1107
- }
1108
- break;
1109
- }
1110
- case "assign_task": {
1111
- const projId = (action.projectId || signal.projectId);
1112
- const tid = action.taskId;
1113
- const assignee = (action.assigneeAddress || action.assignee);
1114
- if (projId && tid && assignee) {
1115
- await runtime.projects.assignTask(projId, tid, assignee);
1116
- if (!json)
1117
- console.log(chalk.green(` [reactive] Assigned task ${tid} to ${assignee}`));
1118
- }
1119
- break;
1120
- }
1121
- case "complete_task":
1122
- case "update_task": {
1123
- const projId = (action.projectId || signal.projectId);
1124
- const tid = action.taskId;
1125
- if (projId && tid) {
1126
- const updates = {};
1127
- if (action.action === "complete_task") {
1128
- updates.status = "completed";
1129
- }
1130
- else {
1131
- if (action.status)
1132
- updates.status = action.status;
1133
- if (action.title)
1134
- updates.title = action.title;
1135
- if (action.description)
1136
- updates.description = action.description;
1137
- if (action.priority)
1138
- updates.priority = action.priority;
1139
- if (action.milestoneId !== undefined)
1140
- updates.milestoneId = action.milestoneId;
1141
- if (action.labels)
1142
- updates.labels = action.labels;
1143
- if (action.dueDate)
1144
- updates.dueDate = action.dueDate;
1145
- }
1146
- await runtime.connection.request("PATCH", `/v1/projects/${projId}/tasks/${tid}`, updates);
1147
- }
1148
- break;
1149
- }
1150
- case "find_agents":
1151
- case "find_matching_agents": {
1152
- const skills = action.skills ?? [];
1153
- if (skills.length) {
1154
- const matchResult = await runtime.matching.findAgents(skills, {
1155
- count: action.count,
1156
- });
1157
- if (!json)
1158
- console.log(chalk.dim(` [reactive] Found ${matchResult.total} matching agents for [${skills.join(", ")}]`));
1159
- }
1160
- break;
1161
- }
1162
- case "assemble_team": {
1163
- const desc = content || action.description || "";
1164
- if (desc) {
1165
- const teamResult = await runtime.matching.assembleTeam({
1166
- description: desc,
1167
- requiredSkills: action.requiredSkills,
1168
- teamSize: action.teamSize,
1169
- });
1170
- if (!json)
1171
- console.log(chalk.dim(` [reactive] Team assembled: ${teamResult.members.length} members, ${Math.round(teamResult.coverageScore * 100)}% coverage`));
1172
- }
1173
- break;
1174
- }
1175
- case "accept_invitation":
1176
- case "decline_invitation": {
1177
- const invId = (action.invitationId || signal.invitationId);
1178
- if (invId) {
1179
- const verb = action.action === "accept_invitation" ? "accept" : "decline";
1180
- await runtime.connection.request("POST", `/v1/teams/invitations/${invId}/${verb}`, {});
1181
- if (!json)
1182
- console.log(chalk.dim(` [reactive] Team invitation ${verb}ed: ${invId.slice(0, 8)}...`));
1183
- }
1184
- break;
1185
- }
1186
- // ── Marketplace actions ──
1187
- case "create_listing":
1188
- case "list_service": {
1189
- const title = (content || action.title);
1190
- const desc = action.description || "";
1191
- const category = action.category || "general";
1192
- if (title) {
1193
- const relay = await prepareSignRelay(runtime.connection, "/v1/prepare/service/list", {
1194
- title, description: desc, category,
1195
- pricingModel: action.pricingModel ?? 0,
1196
- priceAmount: action.priceAmount ?? "0",
1197
- tags: action.tags ?? [],
1198
- ...(action.tokenAddress ? { tokenAddress: action.tokenAddress } : {}),
1199
- });
1200
- if (!json)
1201
- console.log(chalk.green(` [reactive] Listed service "${title}" (tx: ${relay.txHash})`));
1202
- }
1203
- break;
1204
- }
1205
- case "create_agreement": {
1206
- const listingId = action.listingId;
1207
- const terms = (content || action.terms);
1208
- const deadline = (action.deadline ?? Math.floor(Date.now() / 1000) + 7 * 86400);
1209
- if (listingId != null && terms) {
1210
- const relay = await prepareSignRelay(runtime.connection, "/v1/prepare/service/agree", {
1211
- listingId, terms, deadline,
1212
- tokenAmount: action.tokenAmount ?? "0",
1213
- ...(action.tokenAddress ? { tokenAddress: action.tokenAddress } : {}),
1214
- });
1215
- if (!json)
1216
- console.log(chalk.green(` [reactive] Created agreement for listing #${listingId} (tx: ${relay.txHash})`));
1217
- }
1218
- break;
1219
- }
1220
- case "deliver_work": {
1221
- const agId = action.agreementId;
1222
- const deliveryCid = (content || action.deliveryCid);
1223
- if (agId != null && deliveryCid) {
1224
- const relay = await prepareSignRelay(runtime.connection, "/v1/prepare/service/deliver", {
1225
- agreementId: agId, deliveryCid,
1226
- });
1227
- if (!json)
1228
- console.log(chalk.green(` [reactive] Delivered work for agreement #${agId} (tx: ${relay.txHash})`));
1229
- }
1230
- break;
1231
- }
1232
- case "settle_agreement": {
1233
- const agId = action.agreementId;
1234
- if (agId != null) {
1235
- const relay = await prepareSignRelay(runtime.connection, "/v1/prepare/service/settle", {
1236
- agreementId: agId,
1237
- });
1238
- if (!json)
1239
- console.log(chalk.green(` [reactive] Settled agreement #${agId} (tx: ${relay.txHash})`));
1240
- }
1241
- break;
1242
- }
1243
- case "dispute_agreement": {
1244
- const agId = action.agreementId;
1245
- if (agId != null) {
1246
- const relay = await prepareSignRelay(runtime.connection, "/v1/prepare/service/dispute", {
1247
- agreementId: agId,
1248
- });
1249
- if (!json)
1250
- console.log(chalk.green(` [reactive] Disputed agreement #${agId} (tx: ${relay.txHash})`));
1251
- }
1252
- break;
1253
- }
1254
- case "cancel_agreement": {
1255
- const agId = action.agreementId;
1256
- if (agId != null) {
1257
- const relay = await prepareSignRelay(runtime.connection, "/v1/prepare/service/cancel", {
1258
- agreementId: agId,
1259
- });
1260
- if (!json)
1261
- console.log(chalk.green(` [reactive] Cancelled agreement #${agId} (tx: ${relay.txHash})`));
1262
- }
1263
- break;
1264
- }
1265
- case "expire_dispute": {
1266
- const agId = action.agreementId;
1267
- if (agId != null) {
1268
- const relay = await prepareSignRelay(runtime.connection, "/v1/prepare/service/expire-dispute", {
1269
- agreementId: agId,
1270
- });
1271
- if (!json)
1272
- console.log(chalk.green(` [reactive] Expired dispute for agreement #${agId} (tx: ${relay.txHash})`));
1273
- }
1274
- break;
1275
- }
1276
- case "expire_delivered": {
1277
- const agId = action.agreementId;
1278
- if (agId != null) {
1279
- const relay = await prepareSignRelay(runtime.connection, "/v1/prepare/service/expire-delivered", {
1280
- agreementId: agId,
1281
- });
1282
- if (!json)
1283
- console.log(chalk.green(` [reactive] Expired delivered for agreement #${agId} (tx: ${relay.txHash})`));
1284
- }
1285
- break;
1286
- }
1287
- case "submit_review": {
1288
- const agId = action.agreementId;
1289
- const rating = action.rating;
1290
- const comment = (content || action.comment || "");
1291
- if (agId != null && rating != null) {
1292
- await runtime.marketplace.submitReview(agId, rating, comment);
1293
- if (!json)
1294
- console.log(chalk.green(` [reactive] Submitted review for agreement #${agId} (${rating}/5)`));
1295
- }
1296
- break;
1297
- }
1298
- case "send_agreement_message": {
1299
- const agId = action.agreementId;
1300
- const msgType = action.messageType || "general";
1301
- const msgContent = (content || action.content);
1302
- if (agId != null && msgContent) {
1303
- const msgBody = { messageType: msgType, content: msgContent };
1304
- if (action.attachmentCid)
1305
- msgBody.attachmentCid = action.attachmentCid;
1306
- await runtime.connection.request("POST", `/v1/marketplace/agreements/${agId}/messages`, msgBody);
1307
- if (!json)
1308
- console.log(chalk.green(` [reactive] Sent ${msgType} message for agreement #${agId}`));
1309
- }
1310
- break;
1311
- }
1312
- case "create_bounty": {
1313
- const payload = action;
1314
- const title = payload?.title;
1315
- const description = payload?.description ?? content ?? "";
1316
- const community = payload?.community ?? "";
1317
- const deadline = payload?.deadline ?? Math.floor(Date.now() / 1000) + 604800; // 7 days
1318
- const tokenRewardAmount = payload?.tokenRewardAmount ?? "0";
1319
- if (!title)
1320
- throw new Error("create_bounty requires title");
1321
- const relay = await prepareSignRelay(runtime.connection, "/v1/prepare/bounty", {
1322
- title, description, community, deadline, tokenRewardAmount,
1323
- });
1324
- if (!json)
1325
- console.log(chalk.green(` [reactive] Created bounty "${title}" (tx: ${relay.txHash})`));
1326
- break;
1327
- }
1328
- case "post_reply": {
1329
- const parentCid = (action.parentCid ?? action.sourceId ?? "");
1330
- if (!parentCid)
1331
- throw new Error("post_reply requires parentCid");
1332
- const replyContent = (content ?? action.body ?? "");
1333
- const replyCommunity = (action.community ?? "");
1334
- await runtime.memory.publishComment({ parentCid, body: replyContent, community: replyCommunity });
1335
- break;
1336
- }
1337
- case "propose_collab": {
1338
- const collabTarget = (action.targetAddress ?? action.recipientAddress ?? target);
1339
- if (!collabTarget)
1340
- throw new Error("propose_collab requires targetAddress");
1341
- const msg = content || "I'd like to collaborate with you!";
1342
- await runtime.inbox.send({ to: collabTarget, content: msg });
1343
- break;
1344
- }
1345
- case "create_bundle": {
1346
- const bundleTitle = action.title;
1347
- if (!bundleTitle)
1348
- throw new Error("create_bundle requires title");
1349
- const bundleDesc = content || action.description || "";
1350
- const domain = action.domain || "";
1351
- const relay = await prepareSignRelay(runtime.connection, "/v1/prepare/bundle", {
1352
- title: bundleTitle, description: bundleDesc, domain,
1353
- });
1354
- if (!json)
1355
- console.log(chalk.green(` [reactive] Created bundle "${bundleTitle}" (tx: ${relay.txHash})`));
1356
- break;
1357
- }
1358
- case "update_service": {
1359
- const listingId = action.listingId;
1360
- if (!listingId)
1361
- throw new Error("update_service requires listingId");
1362
- const relay = await prepareSignRelay(runtime.connection, "/v1/prepare/service/update", {
1363
- listingId, ...action,
1364
- });
1365
- if (!json)
1366
- console.log(chalk.green(` [reactive] Updated service listing #${listingId} (tx: ${relay.txHash})`));
1367
- break;
1368
- }
1369
- case "approve_bounty_work": {
1370
- const bountyId = (action.bountyId || signal.bountyId);
1371
- if (!bountyId)
1372
- throw new Error("approve_bounty_work requires bountyId");
1373
- const relay = await prepareSignRelay(runtime.connection, `/v1/prepare/bounty/${bountyId}/approve`, {});
1374
- if (!json)
1375
- console.log(chalk.green(` [reactive] Approved bounty work: ${bountyId} (tx: ${relay.txHash})`));
1376
- break;
1377
- }
1378
- case "dispute_bounty_work": {
1379
- const bountyId = (action.bountyId || signal.bountyId);
1380
- if (!bountyId)
1381
- throw new Error("dispute_bounty_work requires bountyId");
1382
- const relay = await prepareSignRelay(runtime.connection, `/v1/prepare/bounty/${bountyId}/dispute`, {});
1383
- if (!json)
1384
- console.log(chalk.green(` [reactive] Disputed bounty work: ${bountyId} (tx: ${relay.txHash})`));
1385
- break;
1386
- }
1387
- case "cancel_bounty": {
1388
- const bountyId = (action.bountyId || signal.bountyId);
1389
- if (!bountyId)
1390
- throw new Error("cancel_bounty requires bountyId");
1391
- const relay = await prepareSignRelay(runtime.connection, `/v1/prepare/bounty/${bountyId}/cancel`, {});
1392
- if (!json)
1393
- console.log(chalk.green(` [reactive] Cancelled bounty: ${bountyId} (tx: ${relay.txHash})`));
1394
- break;
1395
- }
1396
- case "unclaim_bounty": {
1397
- const bountyId = (action.bountyId || signal.bountyId);
1398
- if (!bountyId)
1399
- throw new Error("unclaim_bounty requires bountyId");
1400
- const relay = await prepareSignRelay(runtime.connection, `/v1/prepare/bounty/${bountyId}/unclaim`, {});
1401
- if (!json)
1402
- console.log(chalk.green(` [reactive] Unclaimed bounty: ${bountyId} (tx: ${relay.txHash})`));
1403
- break;
1404
- }
1405
- case "grant": {
1406
- const projId = action.projectId;
1407
- const bountyId = (action.bountyId || signal.bountyId);
1408
- const reqId = action.requestId;
1409
- if (!projId || !bountyId || !reqId)
1410
- throw new Error("grant requires projectId, bountyId, requestId");
1411
- await runtime.connection.request("POST", `/v1/projects/${projId}/bounties/${bountyId}/grant-access`, { requestId: reqId });
1412
- if (!json)
1413
- console.log(chalk.green(` [reactive] Granted bounty access: ${bountyId} request ${reqId}`));
1414
- break;
1415
- }
1416
- case "deny": {
1417
- const projId = action.projectId;
1418
- const bountyId = (action.bountyId || signal.bountyId);
1419
- const reqId = action.requestId;
1420
- if (!projId || !bountyId || !reqId)
1421
- throw new Error("deny requires projectId, bountyId, requestId");
1422
- await runtime.connection.request("POST", `/v1/projects/${projId}/bounties/${bountyId}/deny-access`, { requestId: reqId });
1423
- if (!json)
1424
- console.log(chalk.green(` [reactive] Denied bounty access: ${bountyId} request ${reqId}`));
1425
- break;
1426
- }
1427
- case "workspace_create": {
1428
- const wsName = (action.name || content);
1429
- if (wsName) {
1430
- const ws = await runtime.workspaces.create({ name: wsName, description: action.description });
1431
- if (!json)
1432
- console.log(chalk.green(` [reactive] Created workspace: ${ws.id}`));
1433
- }
1434
- break;
1435
- }
1436
- case "workspace_set": {
1437
- const wsId = action.workspaceId;
1438
- const wsKey = action.key;
1439
- const wsVal = action.value ?? content;
1440
- if (wsId && wsKey) {
1441
- await runtime.workspaces.setState(wsId, wsKey, wsVal);
1442
- if (!json)
1443
- console.log(chalk.green(` [reactive] Set ${wsKey} in workspace ${wsId}`));
1444
- }
1445
- break;
1446
- }
1447
- case "workspace_snapshot": {
1448
- const snapWsId = action.workspaceId;
1449
- if (snapWsId) {
1450
- await runtime.workspaces.createSnapshot(snapWsId, action.label);
1451
- if (!json)
1452
- console.log(chalk.green(` [reactive] Created snapshot in workspace ${snapWsId}`));
1453
- }
1454
- break;
1455
- }
1456
- case "propose_action": {
1457
- const wsId = action.workspaceId;
1458
- const title = (action.title || content);
1459
- if (wsId && title) {
1460
- const prop = await runtime.workspaces.createProposal(wsId, {
1461
- title,
1462
- description: action.description,
1463
- actionType: action.actionType ?? "custom",
1464
- actionPayload: action.actionPayload,
1465
- quorumType: action.quorumType,
1466
- quorumThreshold: action.quorumThreshold,
1467
- });
1468
- if (!json)
1469
- console.log(chalk.green(` [reactive] Created proposal: ${prop.proposal?.id}`));
1470
- }
1471
- break;
1472
- }
1473
- case "vote_proposal": {
1474
- const wsId = action.workspaceId;
1475
- const proposalId = action.proposalId;
1476
- if (wsId && proposalId && action.vote !== undefined) {
1477
- await runtime.workspaces.vote(wsId, proposalId, action.vote, action.reason);
1478
- if (!json)
1479
- console.log(chalk.green(` [reactive] Voted on proposal ${proposalId}`));
1480
- }
1481
- break;
1482
- }
1483
- case "cancel_proposal": {
1484
- const wsId = action.workspaceId;
1485
- const proposalId = action.proposalId;
1486
- if (wsId && proposalId) {
1487
- await runtime.workspaces.cancelProposal(wsId, proposalId);
1488
- if (!json)
1489
- console.log(chalk.green(` [reactive] Cancelled proposal ${proposalId}`));
1490
- }
1491
- break;
1492
- }
1493
- // ── Real World Actions ──
1494
- case "egress_request":
1495
- case "http_request": {
1496
- const targetUrl = action.url ?? "";
1497
- const httpMethod = (action.method ?? "GET").toUpperCase();
1498
- if (!targetUrl)
1499
- throw new Error("egress_request requires url");
1500
- const httpResult = await runtime.tools.httpRequest(targetUrl, httpMethod, {
1501
- headers: action.headers,
1502
- body: action.body,
1503
- timeout: action.timeout,
1504
- credentialService: action.credentialService,
1505
- });
1506
- if (!json)
1507
- console.log(chalk.green(` [reactive] HTTP ${httpMethod} ${targetUrl.slice(0, 60)} → ${httpResult?.status ?? "ok"}`));
1508
- break;
1509
- }
1510
- case "execute_tool": {
1511
- const toolName = action.toolName ?? "";
1512
- if (!toolName)
1513
- throw new Error("execute_tool requires toolName");
1514
- const toolArgs = (action.args ?? action.arguments ?? {});
1515
- const toolResult = await runtime.tools.executeTool(toolName, toolArgs);
1516
- if (!json)
1517
- console.log(chalk.green(` [reactive] Executed tool: ${toolName}`));
1518
- break;
1519
- }
1520
- case "exec_code": {
1521
- const cmd = action.command ?? "";
1522
- const img = (action.image ?? "node:20-slim");
1523
- const files = (action.files ?? {});
1524
- const timeout = action.timeout;
1525
- const projId = action.projectId;
1526
- if (!cmd)
1527
- throw new Error("exec_code requires command");
1528
- const execResult = await runtime.tools.execCode(cmd, img, { files, timeout, projectId: projId });
1529
- if (!json)
1530
- console.log(chalk.green(` [reactive] Executed code (${img}): exit=${execResult.exitCode}`));
1531
- break;
1532
- }
1533
- case "connect_mcp_server": {
1534
- const serverUrl = (action.serverUrl ?? action.url);
1535
- const serverName = (action.serverName ?? action.name ?? "mcp-server");
1536
- if (!serverUrl)
1537
- throw new Error("connect_mcp_server requires serverUrl");
1538
- await runtime.tools.connectMcpServer(serverUrl, serverName);
1539
- if (!json)
1540
- console.log(chalk.green(` [reactive] Connected MCP server: ${serverUrl.slice(0, 60)}`));
1541
- break;
1542
- }
1543
- case "disconnect_mcp_server": {
1544
- const serverId = (action.serverId ?? action.serverUrl);
1545
- if (!serverId)
1546
- throw new Error("disconnect_mcp_server requires serverId");
1547
- await runtime.tools.disconnectMcpServer(serverId);
1548
- if (!json)
1549
- console.log(chalk.green(` [reactive] Disconnected MCP server: ${serverId.slice(0, 60)}`));
1550
- break;
1551
- }
1552
- case "call_mcp_tool":
1553
- case "use_mcp_tool": {
1554
- const mcpToolName = action.toolName ?? "";
1555
- if (!mcpToolName)
1556
- throw new Error("call_mcp_tool requires toolName");
1557
- const mcpToolArgs = (action.args ?? action.arguments ?? {});
1558
- const mcpResult = await runtime.tools.executeTool(mcpToolName, mcpToolArgs);
1559
- if (!json)
1560
- console.log(chalk.green(` [reactive] MCP tool called: ${mcpToolName}`));
1561
- break;
1562
- }
1563
- case "register_webhook": {
1564
- const source = action.source ?? "";
1565
- if (!source)
1566
- throw new Error("register_webhook requires source");
1567
- await runtime.connection.request("POST", "/v1/agents/me/webhooks", {
1568
- source,
1569
- description: action.description,
1570
- secret: action.secret,
1571
- });
1572
- if (!json)
1573
- console.log(chalk.green(` [reactive] Registered webhook: ${source}`));
1574
- break;
1575
- }
1576
- case "publish_insight": {
1577
- const title = action.title;
1578
- const body = action.body;
1579
- if (title && body) {
1580
- await runtime.insights?.publish({
1581
- title,
1582
- body,
1583
- strategyType: action.strategyType,
1584
- tags: action.tags,
1585
- outcomeScore: action.outcomeScore,
1586
- workspaceId: action.workspaceId,
1587
- });
1588
- if (!json)
1589
- console.log(chalk.green(` [reactive] Published insight: ${title}`));
1590
- }
1591
- break;
1592
- }
1593
- case "cite_insight": {
1594
- const insightId = action.insightId;
1595
- if (insightId) {
1596
- await runtime.insights?.cite(insightId, action.context, action.outcomeScore);
1597
- if (!json)
1598
- console.log(chalk.green(` [reactive] Cited insight ${insightId}`));
1599
- }
1600
- break;
1601
- }
1602
- case "apply_insight": {
1603
- const insightId = action.insightId;
1604
- if (insightId) {
1605
- await runtime.insights?.apply(insightId, action.context, action.outcomeScore);
1606
- if (!json)
1607
- console.log(chalk.green(` [reactive] Applied insight ${insightId}`));
1608
- }
1609
- break;
1610
- }
1611
- case "deposit_treasury": {
1612
- const guildId = action.guildId;
1613
- const amount = action.amount;
1614
- if (guildId && amount) {
1615
- await runtime.guilds.depositTreasury(guildId, amount, action.memo);
1616
- if (!json)
1617
- console.log(chalk.green(` [reactive] Deposited ${amount} to guild ${guildId} treasury`));
1618
- }
1619
- break;
1620
- }
1621
- case "withdraw_treasury": {
1622
- const guildId = action.guildId;
1623
- const amount = action.amount;
1624
- if (guildId && amount) {
1625
- await runtime.guilds.withdrawTreasury(guildId, amount, action.memo);
1626
- if (!json)
1627
- console.log(chalk.green(` [reactive] Withdrew ${amount} from guild ${guildId} treasury`));
1628
- }
1629
- break;
1630
- }
1631
- case "fund_bounty_from_treasury": {
1632
- const guildId = action.guildId;
1633
- const bountyId = action.bountyId;
1634
- const amount = action.amount;
1635
- if (guildId && bountyId && amount) {
1636
- await runtime.guilds.fundBountyFromTreasury(guildId, bountyId, amount, action.proposalId);
1637
- if (!json)
1638
- console.log(chalk.green(` [reactive] Funded bounty ${bountyId} with ${amount} from guild ${guildId}`));
1639
- }
1640
- break;
1641
- }
1642
- case "distribute_revenue": {
1643
- const guildId = action.guildId;
1644
- if (guildId) {
1645
- await runtime.guilds.distributeRevenue(guildId, action.amount);
1646
- if (!json)
1647
- console.log(chalk.green(` [reactive] Distributed revenue for guild ${guildId}`));
1648
- }
1649
- break;
1650
- }
1651
- case "create_swarm": {
1652
- if (action.title && action.subtasks) {
1653
- await runtime.swarms?.create({ title: action.title, description: action.description, workspaceId: action.workspaceId, subtasks: action.subtasks });
1654
- if (!json)
1655
- console.log(chalk.green(` [reactive] Created swarm: ${action.title}`));
1656
- }
1657
- break;
1658
- }
1659
- case "claim_subtask": {
1660
- const stId = action.subtaskId;
1661
- if (stId) {
1662
- await runtime.swarms?.claimSubtask(stId);
1663
- if (!json)
1664
- console.log(chalk.green(` [reactive] Claimed subtask ${stId}`));
1665
- }
1666
- break;
1667
- }
1668
- case "submit_swarm_result": {
1669
- const stId = action.subtaskId;
1670
- if (stId && action.content) {
1671
- await runtime.swarms?.submitResult(stId, action.content, action.resultType);
1672
- if (!json)
1673
- console.log(chalk.green(` [reactive] Submitted result for subtask ${stId}`));
1674
- }
1675
- break;
1676
- }
1677
- case "aggregate_swarm": {
1678
- const swarmId = action.swarmId;
1679
- if (swarmId) {
1680
- await runtime.swarms?.aggregate(swarmId, action.summary);
1681
- if (!json)
1682
- console.log(chalk.green(` [reactive] Aggregated swarm ${swarmId}`));
1683
- }
1684
- break;
1685
- }
1686
- case "record_gap": {
1687
- if (action.queryText) {
1688
- await runtime.specialization?.recordGap({ queryText: action.queryText, queryTags: action.queryTags || [], communityId: action.communityId });
1689
- if (!json)
1690
- console.log(chalk.green(` [reactive] Recorded skill gap: ${action.queryText}`));
1691
- }
1692
- break;
1693
- }
1694
- case "update_proficiency": {
1695
- const domain = action.skillDomain;
1696
- if (domain) {
1697
- await runtime.specialization?.updateProficiency(domain, Number(action.proficiency || 0));
1698
- if (!json)
1699
- console.log(chalk.green(` [reactive] Updated proficiency: ${domain}`));
1700
- }
1701
- break;
1702
- }
1703
- case "generate_recommendations": {
1704
- await runtime.specialization?.generateRecommendations();
1705
- if (!json)
1706
- console.log(chalk.green(` [reactive] Generated specialization recommendations`));
1707
- break;
1708
- }
1709
- case "dismiss_recommendation": {
1710
- const recId = action.recommendationId;
1711
- if (recId) {
1712
- await runtime.specialization?.dismissRecommendation(recId);
1713
- if (!json)
1714
- console.log(chalk.green(` [reactive] Dismissed recommendation ${recId}`));
1715
- }
1716
- break;
1717
- }
1718
- // ── Intents ──
1719
- case "create_intent": {
1720
- const intentRes = await runtime.intents.create({
1721
- title: action.title || action.content || "Untitled intent",
1722
- description: action.description || action.content || "",
1723
- requiredSkills: action.requiredSkills,
1724
- budgetAmount: action.budgetAmount,
1725
- category: action.category,
1726
- tags: action.tags,
1727
- });
1728
- if (!json)
1729
- console.log(chalk.green(` [reactive] Created intent ${intentRes.id}`));
1730
- break;
1731
- }
1732
- case "browse_intents": {
1733
- const browseRes = await runtime.intents.list({
1734
- status: action.status || "open",
1735
- category: action.category,
1736
- q: action.q,
1737
- limit: 20,
1738
- });
1739
- if (!json)
1740
- console.log(chalk.green(` [reactive] Found ${browseRes.total} intents`));
1741
- break;
1742
- }
1743
- case "submit_proposal": {
1744
- const spIntentId = action.intentId;
1745
- if (spIntentId) {
1746
- const proposalRes = await runtime.intents.submitProposal(spIntentId, {
1747
- description: action.description || action.content || "",
1748
- approach: action.approach,
1749
- estimatedCost: action.estimatedCost,
1750
- estimatedDurationHours: action.estimatedDurationHours,
1751
- });
1752
- if (!json)
1753
- console.log(chalk.green(` [reactive] Submitted proposal ${proposalRes.id}`));
1754
- }
1755
- break;
1756
- }
1757
- case "accept_proposal": {
1758
- const apIntentId = action.intentId;
1759
- const apProposalId = action.proposalId;
1760
- if (apIntentId && apProposalId) {
1761
- await runtime.intents.acceptProposal(apIntentId, apProposalId);
1762
- if (!json)
1763
- console.log(chalk.green(` [reactive] Accepted proposal ${apProposalId}`));
1764
- }
1765
- break;
1766
- }
1767
- case "reject_proposal": {
1768
- const rpIntentId = action.intentId;
1769
- const rpProposalId = action.proposalId;
1770
- if (rpIntentId && rpProposalId) {
1771
- const rpReason = action.content || action.reason || "";
1772
- await runtime.intents.rejectProposal(rpIntentId, rpProposalId, rpReason);
1773
- if (!json)
1774
- console.log(chalk.green(` [reactive] Rejected proposal ${rpProposalId}`));
1775
- }
1776
- break;
1777
- }
1778
- case "cancel_intent": {
1779
- const ciId = action.intentId;
1780
- if (ciId) {
1781
- await runtime.intents.cancel(ciId);
1782
- if (!json)
1783
- console.log(chalk.green(` [reactive] Cancelled intent ${ciId}`));
1784
- }
1785
- break;
1786
- }
1787
- case "complete_intent": {
1788
- const coiId = action.intentId;
1789
- if (coiId) {
1790
- await runtime.intents.complete(coiId);
1791
- if (!json)
1792
- console.log(chalk.green(` [reactive] Completed intent ${coiId}`));
1793
- }
1794
- break;
1795
- }
1796
- case "withdraw_proposal": {
1797
- const wpIntentId = action.intentId;
1798
- const wpProposalId = action.proposalId;
1799
- if (wpIntentId && wpProposalId) {
1800
- await runtime.intents.withdrawProposal(wpIntentId, wpProposalId);
1801
- if (!json)
1802
- console.log(chalk.green(` [reactive] Withdrew proposal ${wpProposalId}`));
1803
- }
1804
- break;
1805
- }
1806
- case "query_oracle": {
1807
- const oEntityType = action.entityType;
1808
- const oEntityId = action.entityId;
1809
- if (oEntityType && oEntityId) {
1810
- let oracleRes;
1811
- switch (oEntityType) {
1812
- case "project":
1813
- oracleRes = await runtime.oracle.getProjectSignals(oEntityId);
1814
- break;
1815
- case "agent":
1816
- oracleRes = await runtime.oracle.getAgentSignals(oEntityId);
1817
- break;
1818
- case "intent":
1819
- oracleRes = await runtime.oracle.getIntentSignals(oEntityId);
1820
- break;
1821
- case "guild":
1822
- oracleRes = await runtime.oracle.getGuildSignals(oEntityId);
1823
- break;
1824
- }
1825
- if (!json && oracleRes)
1826
- console.log(chalk.green(` [reactive] Oracle ${oEntityType}/${oEntityId}: ${JSON.stringify(oracleRes.signals).slice(0, 100)}`));
1827
- }
1828
- break;
1829
- }
1830
- case "create_search_subscription": {
1831
- const subRes = await runtime.discovery.createSubscription({
1832
- label: action.label || "Search subscription",
1833
- query: action.query || action.content || "",
1834
- types: action.types,
1835
- frequencyMinutes: action.frequencyMinutes,
1836
- });
1837
- if (!json)
1838
- console.log(chalk.green(` [reactive] Created search subscription ${subRes.id}`));
1839
- break;
1840
- }
1841
- // ── Clawnch Token Launching ──
1842
- case "preview_token_launch": {
1843
- const prevRes = await runtime.connection.request("POST", "/v1/clawnch/preview", { tokenName: action.tokenName, tokenTicker: action.tokenTicker, description: action.description || action.content, imageUrl: action.imageUrl });
1844
- if (!json)
1845
- console.log(chalk.green(` [reactive] Token preview: ${prevRes?.launch ? "OK" : "done"}`));
1846
- break;
1847
- }
1848
- case "launch_token": {
1849
- const launchRes = await runtime.connection.request("POST", "/v1/clawnch/launch", { tokenName: action.tokenName, tokenTicker: action.tokenTicker, description: action.description || action.content, imageUrl: action.imageUrl });
1850
- const tokenAddr = launchRes?.launch;
1851
- if (!json)
1852
- console.log(chalk.green(` [reactive] Launched token ${tokenAddr?.token_address ?? "pending"}`));
1853
- break;
1854
- }
1855
- case "claim_clawnch_fees": {
1856
- const claimAddr = action.tokenAddress;
1857
- if (claimAddr) {
1858
- await runtime.connection.request("POST", "/v1/clawnch/claim-fees", { tokenAddress: claimAddr });
1859
- if (!json)
1860
- console.log(chalk.green(` [reactive] Claimed fees for ${claimAddr.slice(0, 10)}...`));
1861
- }
1862
- break;
1863
- }
1864
- case "get_token_analytics": {
1865
- const analyticsAddr = action.tokenAddress;
1866
- if (analyticsAddr) {
1867
- await runtime.connection.request("GET", `/v1/clawnch/analytics/token/${analyticsAddr}`);
1868
- if (!json)
1869
- console.log(chalk.green(` [reactive] Token analytics for ${analyticsAddr.slice(0, 10)}...`));
1870
- }
1871
- break;
1872
- }
1873
- case "send_email": {
1874
- const emailTo = action.to;
1875
- const subject = (action.subject || content?.slice(0, 100));
1876
- const emailBody = (action.body || content);
1877
- if (!emailTo || !subject || !emailBody)
1878
- throw new Error("send_email requires to, subject, body");
1879
- await runtime.connection.request("POST", "/v1/email/send", { to: emailTo, subject, bodyText: emailBody });
1880
- if (!json)
1881
- console.log(chalk.dim(` [reactive] Email sent to ${emailTo.slice(0, 30)}`));
1882
- break;
1883
- }
1884
- case "reply_email": {
1885
- const msgId = action.messageId;
1886
- const replyBody = (action.body || content);
1887
- if (!msgId || !replyBody)
1888
- throw new Error("reply_email requires messageId and body");
1889
- await runtime.connection.request("POST", `/v1/email/${msgId}/reply`, { bodyText: replyBody });
1890
- if (!json)
1891
- console.log(chalk.dim(` [reactive] Replied to email ${msgId.slice(0, 10)}...`));
1892
- break;
1893
- }
1894
- case "check_email": {
1895
- await runtime.connection.request("GET", "/v1/email/messages?direction=inbound&limit=10");
1896
- if (!json)
1897
- console.log(chalk.dim(` [reactive] Checked email inbox`));
1898
- break;
1899
- }
1900
- case "create_email_inbox": {
1901
- const localPart = action.username;
1902
- if (!localPart)
1903
- throw new Error("create_email_inbox requires username");
1904
- await runtime.connection.request("POST", "/v1/email/inbox", { username: localPart, displayName: action.displayName });
1905
- if (!json)
1906
- console.log(chalk.dim(` [reactive] Created email inbox: ${localPart}`));
1907
- break;
1908
- }
1909
- // ── Skill Registry ──────────────────────────────────────────────
1910
- case "search_skills": {
1911
- const q = action.query || action.q || "";
1912
- const category = action.category;
1913
- const limit = action.limit || 20;
1914
- const params = new URLSearchParams();
1915
- if (q)
1916
- params.set("q", String(q));
1917
- if (category)
1918
- params.set("category", String(category));
1919
- params.set("limit", String(limit));
1920
- await runtime.connection.request("GET", `/v1/skills/registry?${params.toString()}`);
1921
- if (!json)
1922
- console.log(chalk.dim(` [reactive] Searched skills: "${q}"`));
1923
- break;
1924
- }
1925
- case "publish_skill": {
1926
- const name = action.name;
1927
- if (!name)
1928
- throw new Error("publish_skill requires name");
1929
- await runtime.connection.request("POST", "/v1/skills/registry", {
1930
- name,
1931
- description: action.description,
1932
- packageType: action.packageType || "skill_md",
1933
- category: action.category || "other",
1934
- tags: action.tags,
1935
- content: action.content || content,
1936
- githubUrl: action.githubUrl,
1937
- npmPackage: action.npmPackage,
1938
- version: action.version || "1.0.0",
1939
- });
1940
- if (!json)
1941
- console.log(chalk.dim(` [reactive] Published skill: ${name}`));
1942
- break;
1943
- }
1944
- case "install_skill": {
1945
- const skillId = action.skillId || action.skill_id;
1946
- if (!skillId)
1947
- throw new Error("install_skill requires skillId");
1948
- await runtime.connection.request("POST", `/v1/skills/registry/${skillId}/install`);
1949
- if (!json)
1950
- console.log(chalk.dim(` [reactive] Installed skill: ${skillId}`));
1951
- break;
1952
- }
1953
- case "review_skill": {
1954
- const skillId = action.skillId || action.skill_id;
1955
- const rating = action.rating;
1956
- if (!skillId || !rating)
1957
- throw new Error("review_skill requires skillId and rating");
1958
- await runtime.connection.request("POST", `/v1/skills/registry/${skillId}/review`, {
1959
- rating, review: action.review || content,
1960
- });
1961
- if (!json)
1962
- console.log(chalk.dim(` [reactive] Reviewed skill: ${skillId} (${rating}/5)`));
1963
- break;
1964
- }
1965
- case "trending_skills": {
1966
- const limit = action.limit || 20;
1967
- await runtime.connection.request("GET", `/v1/skills/registry/trending?limit=${limit}`);
1968
- if (!json)
1969
- console.log(chalk.dim(` [reactive] Fetched trending skills`));
1970
- break;
1971
- }
1972
- // ── Agent Memory ────────────────────────────────────────────────
1973
- case "store_memory": {
1974
- const memContent = action.body || content;
1975
- if (!memContent)
1976
- throw new Error("store_memory requires content");
1977
- await runtime.connection.request("POST", "/v1/agent-memory/store", {
1978
- type: action.memoryType || action.type || "semantic",
1979
- content: memContent, importance: action.importance, tags: action.tags,
1980
- source: action.source, metadata: action.metadata,
1981
- });
1982
- if (!json)
1983
- console.log(chalk.dim(` [reactive] Stored memory`));
1984
- break;
1985
- }
1986
- case "recall_memory": {
1987
- const query = action.query || action.q;
1988
- if (!query)
1989
- throw new Error("recall_memory requires query");
1990
- const rtypes = action.types
1991
- || ((action.memoryType || action.type) ? [String(action.memoryType || action.type)] : undefined);
1992
- await runtime.connection.request("POST", "/v1/agent-memory/recall", {
1993
- query, types: rtypes, limit: action.limit || 10,
1994
- });
1995
- if (!json)
1996
- console.log(chalk.dim(` [reactive] Recalled memories for: "${query}"`));
1997
- break;
1998
- }
1999
- case "list_memories": {
2000
- const type = action.memoryType || action.type || "";
2001
- const limit = action.limit || 20;
2002
- const params = new URLSearchParams();
2003
- if (type)
2004
- params.set("type", String(type));
2005
- params.set("limit", String(limit));
2006
- await runtime.connection.request("GET", `/v1/agent-memory/list?${params.toString()}`);
2007
- if (!json)
2008
- console.log(chalk.dim(` [reactive] Listed memories`));
2009
- break;
2010
- }
2011
- case "memory_stats": {
2012
- await runtime.connection.request("GET", "/v1/agent-memory/stats");
2013
- if (!json)
2014
- console.log(chalk.dim(` [reactive] Fetched memory stats`));
2015
- break;
2016
- }
2017
- case "export_memories": {
2018
- await runtime.connection.request("POST", "/v1/agent-memory/export");
2019
- if (!json)
2020
- console.log(chalk.dim(` [reactive] Exported memories`));
2021
- break;
2022
- }
2023
- case "import_memories": {
2024
- const pack = action.pack || action.memories;
2025
- if (!pack)
2026
- throw new Error("import_memories requires pack data");
2027
- await runtime.connection.request("POST", "/v1/agent-memory/import", pack);
2028
- if (!json)
2029
- console.log(chalk.dim(` [reactive] Imported memories`));
2030
- break;
2031
- }
2032
- // ── Forge (Agent Deployment) ────────────────────────────────────
2033
- case "forge_deploy": {
2034
- const forgeBundleId = action.bundleId;
2035
- const forgeAgentAddr = action.agentAddress;
2036
- const forgeSoulCid = action.soulCid;
2037
- if (!forgeBundleId)
2038
- throw new Error("forge_deploy requires bundleId (number)");
2039
- if (!forgeAgentAddr)
2040
- throw new Error("forge_deploy requires agentAddress");
2041
- if (!forgeSoulCid)
2042
- throw new Error("forge_deploy requires soulCid");
2043
- const relayResult = await prepareSignRelay(runtime.connection, "/v1/prepare/forge", {
2044
- bundleId: forgeBundleId, agentAddress: forgeAgentAddr, soulCid: forgeSoulCid, deploymentFee: action.deploymentFee,
2045
- });
2046
- if (!json)
2047
- console.log(chalk.dim(` [reactive] Forge deployed: ${forgeBundleId} (tx: ${relayResult.txHash})`));
2048
- break;
2049
- }
2050
- case "forge_spawn": {
2051
- const spawnBundleId = action.bundleId;
2052
- const childAddress = action.childAddress || action.parentAddress;
2053
- const spawnSoulCid = action.soulCid;
2054
- if (!spawnBundleId)
2055
- throw new Error("forge_spawn requires bundleId (number)");
2056
- if (!childAddress)
2057
- throw new Error("forge_spawn requires childAddress");
2058
- if (!spawnSoulCid)
2059
- throw new Error("forge_spawn requires soulCid");
2060
- const relayResult = await prepareSignRelay(runtime.connection, "/v1/prepare/forge/spawn", {
2061
- bundleId: spawnBundleId, childAddress, soulCid: spawnSoulCid, deploymentFee: action.deploymentFee,
2062
- });
2063
- if (!json)
2064
- console.log(chalk.dim(` [reactive] Forge spawned child: ${childAddress} (tx: ${relayResult.txHash})`));
2065
- break;
2066
- }
2067
- case "forge_update_soul": {
2068
- const agentId = action.agentId || action.forgeId;
2069
- if (!agentId)
2070
- throw new Error("forge_update_soul requires agentId");
2071
- const relayResult = await prepareSignRelay(runtime.connection, `/v1/prepare/forge/${agentId}/soul`, {
2072
- soulCid: action.soulCid, metadata: action.metadata,
2073
- });
2074
- if (!json)
2075
- console.log(chalk.dim(` [reactive] Forge soul updated: ${agentId} (tx: ${relayResult.txHash})`));
2076
- break;
2077
- }
2078
- // ── Teaching Exchanges ──
2079
- case "propose_teaching": {
2080
- const learnerAddress = action.learnerAddress;
2081
- const goal = (action.goal ?? action.suggestedContent);
2082
- const offerings = action.offerings;
2083
- if (!learnerAddress || !goal || !offerings?.length)
2084
- throw new Error("propose_teaching requires learnerAddress, goal, offerings[]");
2085
- await runtime.connection.request("POST", "/v1/teaching/propose", { learnerAddress, goal, offerings });
2086
- break;
2087
- }
2088
- case "accept_teaching": {
2089
- const exchangeId = action.exchangeId;
2090
- if (!exchangeId)
2091
- throw new Error("accept_teaching requires exchangeId");
2092
- await runtime.connection.request("POST", `/v1/teaching/${exchangeId}/accept`, {});
2093
- break;
2094
- }
2095
- case "deliver_teaching": {
2096
- const exchangeId = action.exchangeId;
2097
- if (!exchangeId)
2098
- throw new Error("deliver_teaching requires exchangeId");
2099
- await runtime.connection.request("POST", `/v1/teaching/${exchangeId}/deliver`, { notes: action.notes });
2100
- break;
2101
- }
2102
- case "approve_teaching": {
2103
- const exchangeId = action.exchangeId;
2104
- if (!exchangeId)
2105
- throw new Error("approve_teaching requires exchangeId");
2106
- await runtime.connection.request("POST", `/v1/teaching/${exchangeId}/approve`, { feedback: action.feedback, rating: action.rating });
2107
- break;
2108
- }
2109
- case "reject_teaching": {
2110
- const exchangeId = action.exchangeId;
2111
- if (!exchangeId)
2112
- throw new Error("reject_teaching requires exchangeId");
2113
- await runtime.connection.request("POST", `/v1/teaching/${exchangeId}/reject`, { feedback: action.feedback });
2114
- break;
2115
- }
2116
- case "search_teachers": {
2117
- const goal = (action.goal ?? action.query);
2118
- if (!goal)
2119
- throw new Error("search_teachers requires goal");
2120
- await runtime.connection.request("GET", `/v1/teaching/search-teachers?goal=${encodeURIComponent(goal)}&limit=${action.limit || 10}`);
2121
- break;
2122
- }
2123
- // ── Credit Hire (off-chain marketplace) ──
2124
- case "credit_hire": {
2125
- const listingId = action.listingId;
2126
- const terms = (action.terms ?? action.suggestedContent);
2127
- const creditAmount = action.creditAmount;
2128
- if (!listingId || !terms || !creditAmount)
2129
- throw new Error("credit_hire requires listingId, terms, creditAmount");
2130
- await runtime.connection.request("POST", "/v1/marketplace/credit-hire", { listingId, terms, creditAmount });
2131
- break;
2132
- }
2133
- case "accept_credit_agreement": {
2134
- const agreementId = action.agreementId;
2135
- if (!agreementId)
2136
- throw new Error("accept_credit_agreement requires agreementId");
2137
- await runtime.connection.request("POST", `/v1/marketplace/credit-agreements/${agreementId}/accept`, {});
2138
- break;
2139
- }
2140
- case "deliver_credit_work": {
2141
- const agreementId = action.agreementId;
2142
- if (!agreementId)
2143
- throw new Error("deliver_credit_work requires agreementId");
2144
- await runtime.connection.request("POST", `/v1/marketplace/credit-agreements/${agreementId}/deliver`, { deliveryNotes: action.deliveryNotes });
2145
- break;
2146
- }
2147
- case "complete_credit_agreement": {
2148
- const agreementId = action.agreementId;
2149
- if (!agreementId)
2150
- throw new Error("complete_credit_agreement requires agreementId");
2151
- await runtime.connection.request("POST", `/v1/marketplace/credit-agreements/${agreementId}/complete`, { rating: action.rating, review: action.review });
2152
- break;
2153
- }
2154
- case "cancel_credit_agreement": {
2155
- const agreementId = action.agreementId;
2156
- if (!agreementId)
2157
- throw new Error("cancel_credit_agreement requires agreementId");
2158
- await runtime.connection.request("POST", `/v1/marketplace/credit-agreements/${agreementId}/cancel`, {});
2159
- break;
2160
- }
2161
- // GPU marketplace actions
2162
- case "gpu_search": {
2163
- const result = await runtime.gpu.searchAvailable({
2164
- gpuModel: action.gpuModel,
2165
- minVram: action.minVram,
2166
- status: action.status,
2167
- limit: action.limit || 10,
2168
- });
2169
- if (!json)
2170
- console.log(chalk.dim(` [reactive] GPU search completed: ${JSON.stringify(result)}`));
2171
- break;
2172
- }
2173
- case "gpu_heartbeat": {
2174
- const listingId = Number(action.listingId);
2175
- if (!listingId)
2176
- throw new Error("gpu_heartbeat requires listingId");
2177
- await runtime.gpu.heartbeat({
2178
- listingId,
2179
- status: action.status || "idle",
2180
- gpuModel: action.gpuModel,
2181
- vramGb: action.vramGb,
2182
- gpuTempC: action.gpuTempC,
2183
- gpuUtilization: action.gpuUtilization,
2184
- vramUsedGb: action.vramUsedGb,
2185
- });
2186
- if (!json)
2187
- console.log(chalk.dim(` [reactive] GPU heartbeat sent for listing ${listingId}`));
2188
- break;
2189
- }
2190
- case "gpu_challenge": {
2191
- const listingId = Number(action.listingId);
2192
- const providerAddress = (action.providerAddress || target);
2193
- const challengeInputCid = action.challengeInputCid;
2194
- if (!listingId || !providerAddress || !challengeInputCid)
2195
- throw new Error("gpu_challenge requires listingId, providerAddress, challengeInputCid");
2196
- await runtime.gpu.createChallenge({
2197
- listingId,
2198
- providerAddress,
2199
- challengeInputCid,
2200
- expectedMinTflops: action.expectedMinTflops,
2201
- });
2202
- if (!json)
2203
- console.log(chalk.dim(` [reactive] GPU challenge created for listing ${listingId}`));
2204
- break;
2205
- }
2206
- case "gpu_submit_challenge": {
2207
- const challengeId = action.challengeId;
2208
- const challengeOutputCid = action.challengeOutputCid;
2209
- if (!challengeId || !challengeOutputCid)
2210
- throw new Error("gpu_submit_challenge requires challengeId, challengeOutputCid");
2211
- await runtime.gpu.submitChallengeResult({
2212
- challengeId,
2213
- challengeOutputCid,
2214
- actualTflops: action.actualTflops,
2215
- wallTimeMs: action.wallTimeMs,
2216
- });
2217
- if (!json)
2218
- console.log(chalk.dim(` [reactive] GPU challenge result submitted for ${challengeId}`));
2219
- break;
2220
- }
2221
- case "gpu_submit_attestation": {
2222
- const benchmarkHash = action.benchmarkHash;
2223
- const gpuModel = action.gpuModel;
2224
- const vramGb = action.vramGb;
2225
- if (!benchmarkHash || !gpuModel || !vramGb)
2226
- throw new Error("gpu_submit_attestation requires benchmarkHash, gpuModel, vramGb");
2227
- const result = await runtime.gpu.submitAttestation({
2228
- benchmarkHash,
2229
- gpuModel,
2230
- vramGb,
2231
- computeCapability: action.computeCapability,
2232
- cudaVersion: action.cudaVersion,
2233
- });
2234
- if (!json)
2235
- console.log(chalk.dim(` [reactive] GPU attestation submitted (tx: ${result.txHash})`));
2236
- break;
2237
- }
2238
- case "gpu_update_attestation": {
2239
- const benchmarkHash = action.benchmarkHash;
2240
- if (!benchmarkHash)
2241
- throw new Error("gpu_update_attestation requires benchmarkHash");
2242
- const result = await runtime.gpu.updateAttestation(benchmarkHash);
2243
- if (!json)
2244
- console.log(chalk.dim(` [reactive] GPU attestation updated (tx: ${result.txHash})`));
2245
- break;
2246
- }
2247
- case "gpu_revoke_attestation": {
2248
- const result = await runtime.gpu.revokeAttestation();
2249
- if (!json)
2250
- console.log(chalk.dim(` [reactive] GPU attestation revoked (tx: ${result.txHash})`));
2251
- break;
2252
- }
2253
- case "gpu_rent": {
2254
- const listingId = Number(action.listingId);
2255
- if (!listingId)
2256
- throw new Error("gpu_rent requires listingId");
2257
- const result = await runtime.gpu.rentGpu({
2258
- listingId,
2259
- terms: action.terms,
2260
- durationHours: action.durationHours,
2261
- tokenAmount: action.tokenAmount,
2262
- tokenAddress: action.tokenAddress,
2263
- });
2264
- if (!json)
2265
- console.log(chalk.dim(` [reactive] GPU rented: listing ${listingId} (tx: ${result.txHash})`));
2266
- break;
2267
- }
2268
- // ── Autoresearch tools ─────────────────────────────────────
2269
- case "autoresearch_strategies": {
2270
- const strategy = action.strategy;
2271
- result = strategy
2272
- ? { name: strategy, ...(AUTORESEARCH_STRATEGIES[strategy] ?? { error: `Unknown strategy '${strategy}'` }) }
2273
- : { strategies: Object.entries(AUTORESEARCH_STRATEGIES).map(([n, s]) => ({ name: n, title: s.title, description: s.description, subtaskCount: s.subtasks.length })) };
2274
- if (!json)
2275
- console.log(chalk.dim(` [reactive] Autoresearch strategies listed`));
2276
- break;
2277
- }
2278
- case "autoresearch_parse": {
2279
- const tsv = action.tsvContent;
2280
- if (!tsv)
2281
- throw new Error("autoresearch_parse requires tsvContent");
2282
- result = parseAutoresearchTsv(tsv, action.sinceCommit);
2283
- if (!json)
2284
- console.log(chalk.dim(` [reactive] Parsed autoresearch results`));
2285
- break;
2286
- }
2287
- case "autoresearch_launch_swarm": {
2288
- const strategyName = action.strategy || "full_sweep";
2289
- const config = AUTORESEARCH_STRATEGIES[strategyName];
2290
- if (!config)
2291
- throw new Error(`Unknown strategy '${strategyName}'. Available: ${Object.keys(AUTORESEARCH_STRATEGIES).join(", ")}`);
2292
- const swarmTitle = action.customTitle || `Autoresearch: ${config.title}`;
2293
- result = await runtime.connection.request("POST", "/v1/swarms", {
2294
- title: swarmTitle,
2295
- description: config.description,
2296
- workspaceId: action.workspaceId,
2297
- subtasks: config.subtasks,
2298
- });
2299
- if (!json)
2300
- console.log(chalk.dim(` [reactive] Launched autoresearch swarm: ${swarmTitle}`));
2301
- break;
2302
- }
2303
- case "autoresearch_report": {
2304
- const experiments = action.experiments;
2305
- if (!experiments?.length)
2306
- throw new Error("autoresearch_report requires experiments array");
2307
- const improvementsOnly = action.improvementsOnly !== false;
2308
- const reportResult = { memoriesStored: 0, postsCreated: 0, errors: [] };
2309
- for (const exp of experiments) {
2310
- const memContent = `Experiment [${exp.commit}]: ${exp.description}. Result: val_bpb=${exp.valBpb}` +
2311
- (exp.improvement != null ? ` (${exp.improvement > 0 ? "+" : ""}${exp.improvement.toFixed(6)} bpb)` : "") +
2312
- ` — ${exp.isImprovement ? "improved" : "no improvement"}. Category: ${exp.category}. VRAM: ${exp.peakVramMb}MB.`;
2313
- try {
2314
- await runtime.connection.request("POST", "/v1/agent-memory/store", {
2315
- type: "episodic", content: memContent,
2316
- importance: exp.isImprovement ? 0.8 : 0.3,
2317
- tags: ["autoresearch", exp.category, exp.isImprovement ? "improvement" : "no-improvement"],
2318
- source: "autoresearch",
2319
- });
2320
- reportResult.memoriesStored++;
2321
- }
2322
- catch (e) {
2323
- reportResult.errors.push(`memory:${exp.commit}: ${e.message || e}`);
2324
- }
2325
- if (exp.isImprovement) {
2326
- try {
2327
- await prepareSignRelay(runtime.connection, "/v1/prepare/post", {
2328
- title: `Autoresearch: ${exp.description}`,
2329
- body: `## Autoresearch Finding: ${exp.description}\n\n**val_bpb:** ${exp.valBpb} (improvement: ${Math.abs(exp.improvement || 0).toFixed(6)})\n**Category:** ${exp.category}\n**VRAM:** ${exp.peakVramMb} MB\n**Commit:** \`${exp.commit}\`\n\nThis experiment was run autonomously using Karpathy's autoresearch framework.`,
2330
- tags: ["autoresearch", exp.category, "ml-research"],
2331
- community: action.communityId || "general",
2332
- });
2333
- reportResult.postsCreated++;
2334
- }
2335
- catch (e) {
2336
- reportResult.errors.push(`post:${exp.commit}: ${e.message || e}`);
2337
- }
2338
- }
2339
- }
2340
- result = reportResult;
2341
- if (!json)
2342
- console.log(chalk.dim(` [reactive] Autoresearch report: ${reportResult.memoriesStored} memories, ${reportResult.postsCreated} posts`));
2343
- break;
2344
- }
2345
- case "autoresearch_submit": {
2346
- const subtaskId = action.subtaskId;
2347
- if (!subtaskId)
2348
- throw new Error("autoresearch_submit requires subtaskId");
2349
- const exps = action.experiments || [];
2350
- const improvementExps = exps.filter((e) => e.isImprovement);
2351
- const best = improvementExps.length ? improvementExps.reduce((a, b) => (a.valBpb < b.valBpb ? a : b)) : null;
2352
- const submitContent = {
2353
- total_experiments: action.totalExperiments || exps.length,
2354
- improvements_found: action.improvements || improvementExps.length,
2355
- success_rate: exps.length ? `${((improvementExps.length / exps.length) * 100).toFixed(1)}%` : "0%",
2356
- best_bpb: action.bestBpb || (best ? best.valBpb : null),
2357
- categories_explored: action.categories || {},
2358
- ...(best && { best_experiment: { commit: best.commit, val_bpb: best.valBpb, description: best.description, category: best.category } }),
2359
- ...(improvementExps.length > 0 && { all_improvements: improvementExps.sort((a, b) => a.valBpb - b.valBpb).map((e) => ({ commit: e.commit, val_bpb: e.valBpb, delta: e.improvement, description: e.description })) }),
2360
- };
2361
- result = await runtime.connection.request("POST", `/v1/swarms/subtasks/${encodeURIComponent(subtaskId)}/submit`, { content: submitContent, resultType: "output" });
2362
- if (!json)
2363
- console.log(chalk.dim(` [reactive] Submitted autoresearch results to subtask ${subtaskId}`));
2364
- break;
2365
- }
2366
- case "autoresearch_bundle": {
2367
- const bundleTitle = action.title;
2368
- let bundleExps = action.experiments || [];
2369
- if (!bundleTitle || !bundleExps.length)
2370
- throw new Error("autoresearch_bundle requires title and experiments");
2371
- if (action.improvementsOnly !== false)
2372
- bundleExps = bundleExps.filter((e) => e.isImprovement);
2373
- if (!bundleExps.length) {
2374
- result = { published: false, reason: "no experiments to bundle" };
2375
- break;
2376
- }
2377
- const bestBpb = Math.min(...bundleExps.map((e) => e.valBpb));
2378
- const payload = {
2379
- type: "autoresearch_bundle", version: "1.0", title: bundleTitle,
2380
- description: `Collection of ${bundleExps.length} ML training experiments. Best val_bpb: ${bestBpb.toFixed(6)}.`,
2381
- domain: "machine-learning", tags: ["autoresearch", "ml-training", "llm", ...(action.tags || [])],
2382
- experiment_count: bundleExps.length, best_bpb: bestBpb,
2383
- experiments: bundleExps.map((e) => ({ commit: e.commit || e.commitHash, val_bpb: e.valBpb, peak_vram_mb: e.peakVramMb, status: e.status, description: e.description, category: e.category, improvement: e.improvement })),
2384
- };
2385
- const resource = await runtime.connection.request("POST", "/v1/knowledge/resources", {
2386
- source_type: "custom", title: bundleTitle, description: payload.description, content: JSON.stringify(payload), tags: payload.tags,
2387
- });
2388
- const resourceId = resource?.resourceId || resource?.resource_id || "unknown";
2389
- try {
2390
- const bundle = await prepareSignRelay(runtime.connection, "/v1/prepare/bundle", { name: bundleTitle, description: payload.description, cids: [String(resourceId)], tags: payload.tags, domain: "machine-learning" });
2391
- result = { published: true, title: bundleTitle, experiments: bundleExps.length, resourceId, bundle };
2392
- }
2393
- catch (e) {
2394
- result = { published: false, reason: e.message || String(e), resourceId, contentUploaded: true };
2395
- }
2396
- if (!json)
2397
- console.log(chalk.dim(` [reactive] Autoresearch bundle: ${bundleTitle}`));
2398
- break;
2399
- }
2400
- case "autoresearch_session_summary": {
2401
- const totalExp = action.totalExperiments;
2402
- const bestBpbVal = action.bestBpb;
2403
- if (totalExp == null || bestBpbVal == null)
2404
- throw new Error("autoresearch_session_summary requires totalExperiments and bestBpb");
2405
- const successRate = totalExp > 0 ? ((action.improvements || 0) / totalExp * 100).toFixed(1) : "0";
2406
- const summaryContent = `Autoresearch session summary: ${totalExp} experiments, ${action.improvements || 0} improvements (${successRate}% success rate). Best val_bpb: ${bestBpbVal.toFixed(6)}. ` +
2407
- (action.categories ? `Categories: ${Object.entries(action.categories).map(([k, v]) => `${k}(${v})`).join(", ")}. ` : "") +
2408
- (action.topFindings?.length ? `Key findings: ${action.topFindings.join("; ")}. ` : "") +
2409
- (action.sessionNotes ? `Notes: ${action.sessionNotes}` : "");
2410
- result = await runtime.connection.request("POST", "/v1/agent-memory/store", {
2411
- type: "semantic", content: summaryContent, importance: 0.9,
2412
- tags: ["autoresearch", "session-summary", "ml-research"], source: "autoresearch",
2413
- });
2414
- if (!json)
2415
- console.log(chalk.dim(` [reactive] Stored autoresearch session summary`));
2416
- break;
2417
- }
2418
- // ── Read-only / discovery tools ────────────────────────────
2419
- case "read_feed": {
2420
- const qs = new URLSearchParams();
2421
- if (action.community)
2422
- qs.set("community", action.community);
2423
- if (action.sort)
2424
- qs.set("sort", action.sort);
2425
- if (action.limit)
2426
- qs.set("limit", String(action.limit));
2427
- if (action.skip)
2428
- qs.set("skip", String(action.skip));
2429
- if (action.minScore)
2430
- qs.set("minScore", String(action.minScore));
2431
- if (action.followingOnly)
2432
- qs.set("followingOnly", "true");
2433
- result = await runtime.connection.request("GET", `/v1/index/feed?${qs}`);
2434
- if (!json)
2435
- console.log(chalk.dim(` [reactive] Read feed`));
2436
- break;
2437
- }
2438
- case "check_balance": {
2439
- result = await runtime.connection.request("GET", "/v1/credits/balance");
2440
- if (!json)
2441
- console.log(chalk.dim(` [reactive] Checked balance`));
2442
- break;
2443
- }
2444
- case "check_reputation": {
2445
- const addr = (action.address || target);
2446
- if (!addr)
2447
- throw new Error("check_reputation requires address");
2448
- result = await runtime.connection.request("GET", `/v1/contributions/${encodeURIComponent(addr)}`);
2449
- if (!json)
2450
- console.log(chalk.dim(` [reactive] Checked reputation for ${addr.slice(0, 10)}...`));
2451
- break;
2452
- }
2453
- case "check_token_balance": {
2454
- result = await runtime.connection.request("GET", "/v1/token/balance");
2455
- if (!json)
2456
- console.log(chalk.dim(` [reactive] Checked token balance`));
2457
- break;
2458
- }
2459
- case "check_token_allowance": {
2460
- const tokenAddr = action.tokenAddress;
2461
- const spenderAddr = action.spenderAddress;
2462
- if (!tokenAddr || !spenderAddr)
2463
- throw new Error("check_token_allowance requires tokenAddress and spenderAddress");
2464
- result = await runtime.connection.request("GET", `/v1/token/allowance?tokenAddress=${encodeURIComponent(tokenAddr)}&spenderAddress=${encodeURIComponent(spenderAddr)}`);
2465
- if (!json)
2466
- console.log(chalk.dim(` [reactive] Checked token allowance`));
2467
- break;
2468
- }
2469
- case "discover": {
2470
- const dq = new URLSearchParams();
2471
- if (action.query)
2472
- dq.set("q", action.query);
2473
- if (action.types)
2474
- dq.set("types", action.types);
2475
- if (action.limit)
2476
- dq.set("limit", String(action.limit));
2477
- result = await runtime.connection.request("GET", `/v1/search?${dq}`);
2478
- if (!json)
2479
- console.log(chalk.dim(` [reactive] Discovered content`));
2480
- break;
2481
- }
2482
- case "get_bounty": {
2483
- const bId = (action.id || action.bountyId);
2484
- if (!bId)
2485
- throw new Error("get_bounty requires id");
2486
- result = await runtime.connection.request("GET", `/v1/bounties/${encodeURIComponent(bId)}`);
2487
- if (!json)
2488
- console.log(chalk.dim(` [reactive] Got bounty ${bId}`));
2489
- break;
2490
- }
2491
- case "get_comments": {
2492
- const cid = action.cid;
2493
- if (!cid)
2494
- throw new Error("get_comments requires cid");
2495
- const cqs = new URLSearchParams();
2496
- if (action.limit)
2497
- cqs.set("limit", String(action.limit));
2498
- result = await runtime.connection.request("GET", `/v1/index/content/${encodeURIComponent(cid)}/comments?${cqs}`);
2499
- if (!json)
2500
- console.log(chalk.dim(` [reactive] Got comments for ${cid.slice(0, 10)}...`));
2501
- break;
2502
- }
2503
- case "get_content": {
2504
- const contentCid = action.cid;
2505
- if (!contentCid)
2506
- throw new Error("get_content requires cid");
2507
- result = await runtime.connection.request("GET", `/v1/index/content/${encodeURIComponent(contentCid)}`);
2508
- if (!json)
2509
- console.log(chalk.dim(` [reactive] Got content ${contentCid.slice(0, 10)}...`));
2510
- break;
2511
- }
2512
- case "get_credentials": {
2513
- result = { apiKey: runtime.connection.apiKey, address: runtime.connection.address, gatewayUrl: runtime.connection.gatewayUrl };
2514
- if (!json)
2515
- console.log(chalk.dim(` [reactive] Got credentials`));
2516
- break;
2517
- }
2518
- case "get_email_inbox": {
2519
- result = await runtime.connection.request("GET", "/v1/email/inbox");
2520
- if (!json)
2521
- console.log(chalk.dim(` [reactive] Got email inbox`));
2522
- break;
2523
- }
2524
- case "get_pending_signals": {
2525
- result = await runtime.connection.request("GET", "/v1/proactive/approvals");
2526
- if (!json)
2527
- console.log(chalk.dim(` [reactive] Got pending signals`));
2528
- break;
2529
- }
2530
- case "get_project_commit": {
2531
- const projId = action.projectId;
2532
- const commitId = action.commitId;
2533
- if (!projId || !commitId)
2534
- throw new Error("get_project_commit requires projectId and commitId");
2535
- result = await runtime.connection.request("GET", `/v1/projects/${encodeURIComponent(projId)}/commits/${encodeURIComponent(commitId)}`);
2536
- if (!json)
2537
- console.log(chalk.dim(` [reactive] Got commit ${commitId.slice(0, 8)}`));
2538
- break;
2539
- }
2540
- case "get_second_opinion": {
2541
- const question = action.question;
2542
- if (!question)
2543
- throw new Error("get_second_opinion requires question");
2544
- result = await runtime.connection.request("POST", "/v1/insights", { title: `Question: ${question.slice(0, 80)}`, body: question, strategyType: "question", tags: ["second-opinion"] });
2545
- if (!json)
2546
- console.log(chalk.dim(` [reactive] Posted question for second opinion`));
2547
- break;
2548
- }
2549
- case "get_swarm": {
2550
- const swarmId = action.swarmId;
2551
- if (!swarmId)
2552
- throw new Error("get_swarm requires swarmId");
2553
- result = await runtime.connection.request("GET", `/v1/swarms/${encodeURIComponent(swarmId)}`);
2554
- if (!json)
2555
- console.log(chalk.dim(` [reactive] Got swarm ${swarmId}`));
2556
- break;
2557
- }
2558
- case "get_workspace": {
2559
- const wsId = action.workspaceId;
2560
- if (!wsId)
2561
- throw new Error("get_workspace requires workspaceId");
2562
- result = await runtime.connection.request("GET", `/v1/workspaces/${encodeURIComponent(wsId)}`);
2563
- if (!json)
2564
- console.log(chalk.dim(` [reactive] Got workspace ${wsId}`));
2565
- break;
2566
- }
2567
- case "leaderboard": {
2568
- const lqs = new URLSearchParams();
2569
- if (action.limit)
2570
- lqs.set("limit", String(action.limit));
2571
- result = await runtime.connection.request("GET", `/v1/contributions/leaderboard?${lqs}`);
2572
- if (!json)
2573
- console.log(chalk.dim(` [reactive] Got leaderboard`));
2574
- break;
2575
- }
2576
- case "lookup_agent": {
2577
- const lookupAddr = (action.address || target);
2578
- if (!lookupAddr)
2579
- throw new Error("lookup_agent requires address");
2580
- result = await runtime.connection.request("GET", `/v1/agents/${encodeURIComponent(lookupAddr)}/profile`);
2581
- if (!json)
2582
- console.log(chalk.dim(` [reactive] Looked up agent ${lookupAddr.slice(0, 10)}...`));
2583
- break;
2584
- }
2585
- case "my_profile": {
2586
- const me = await runtime.connection.request("GET", "/v1/agents/me");
2587
- const addr2 = me?.address || runtime.connection.address;
2588
- let contribs = {};
2589
- let balance = {};
2590
- try {
2591
- contribs = await runtime.connection.request("GET", `/v1/contributions/${addr2}`);
2592
- }
2593
- catch { }
2594
- try {
2595
- balance = await runtime.connection.request("GET", "/v1/credits/balance");
2596
- }
2597
- catch { }
2598
- result = { ...me, contributions: contribs, credits: balance };
2599
- if (!json)
2600
- console.log(chalk.dim(` [reactive] Got my profile`));
2601
- break;
2602
- }
2603
- case "search_knowledge": {
2604
- const skqs = new URLSearchParams();
2605
- if (action.query)
2606
- skqs.set("q", action.query);
2607
- if (action.types)
2608
- skqs.set("types", action.types);
2609
- if (action.limit)
2610
- skqs.set("limit", String(action.limit));
2611
- result = await runtime.connection.request("GET", `/v1/search?${skqs}`);
2612
- if (!json)
2613
- console.log(chalk.dim(` [reactive] Searched knowledge`));
2614
- break;
2615
- }
2616
- case "weekly_reward_info": {
2617
- result = await runtime.connection.request("GET", "/v1/rewards/weekly/current");
2618
- if (!json)
2619
- console.log(chalk.dim(` [reactive] Got weekly reward info`));
2620
- break;
2621
- }
2622
- case "check_my_rewards": {
2623
- const rwqs = new URLSearchParams();
2624
- if (action.limit)
2625
- rwqs.set("limit", String(action.limit));
2626
- result = await runtime.connection.request("GET", `/v1/rewards/weekly/me?${rwqs}`);
2627
- if (!json)
2628
- console.log(chalk.dim(` [reactive] Checked my rewards`));
2629
- break;
2630
- }
2631
- // ── List/browse tools ──────────────────────────────────────
2632
- case "list_bounties": {
2633
- const lbqs = new URLSearchParams();
2634
- if (action.community)
2635
- lbqs.set("community", action.community);
2636
- if (action.status != null)
2637
- lbqs.set("status", String(action.status));
2638
- if (action.limit)
2639
- lbqs.set("limit", String(action.limit));
2640
- result = await runtime.connection.request("GET", `/v1/index/bounties?${lbqs}`);
2641
- if (!json)
2642
- console.log(chalk.dim(` [reactive] Listed bounties`));
2643
- break;
2644
- }
2645
- case "list_channels": {
2646
- const lcqs = new URLSearchParams();
2647
- if (action.channelType)
2648
- lcqs.set("channelType", action.channelType);
2649
- if (action.limit)
2650
- lcqs.set("limit", String(action.limit));
2651
- result = await runtime.connection.request("GET", `/v1/channels?${lcqs}`);
2652
- if (!json)
2653
- console.log(chalk.dim(` [reactive] Listed channels`));
2654
- break;
2655
- }
2656
- case "list_communities": {
2657
- const lcmqs = new URLSearchParams();
2658
- if (action.limit)
2659
- lcmqs.set("limit", String(action.limit));
2660
- result = await runtime.connection.request("GET", `/v1/index/communities?${lcmqs}`);
2661
- if (!json)
2662
- console.log(chalk.dim(` [reactive] Listed communities`));
2663
- break;
2664
- }
2665
- case "list_credit_agreements": {
2666
- const lcaqs = new URLSearchParams();
2667
- if (action.role)
2668
- lcaqs.set("role", action.role);
2669
- if (action.status)
2670
- lcaqs.set("status", action.status);
2671
- if (action.limit)
2672
- lcaqs.set("limit", String(action.limit));
2673
- result = await runtime.connection.request("GET", `/v1/marketplace/credit-agreements?${lcaqs}`);
2674
- if (!json)
2675
- console.log(chalk.dim(` [reactive] Listed credit agreements`));
2676
- break;
2677
- }
2678
- case "list_guilds": {
2679
- const lgqs = new URLSearchParams();
2680
- if (action.limit)
2681
- lgqs.set("limit", String(action.limit));
2682
- result = await runtime.connection.request("GET", `/v1/index/guilds?${lgqs}`);
2683
- if (!json)
2684
- console.log(chalk.dim(` [reactive] Listed guilds`));
2685
- break;
2686
- }
2687
- case "list_intents": {
2688
- const liqs = new URLSearchParams();
2689
- if (action.query)
2690
- liqs.set("query", action.query);
2691
- if (action.category)
2692
- liqs.set("category", action.category);
2693
- if (action.status)
2694
- liqs.set("status", action.status);
2695
- if (action.limit)
2696
- liqs.set("limit", String(action.limit));
2697
- result = await runtime.connection.request("GET", `/v1/intents?${liqs}`);
2698
- if (!json)
2699
- console.log(chalk.dim(` [reactive] Listed intents`));
2700
- break;
2701
- }
2702
- case "list_muted": {
2703
- result = await runtime.connection.request("GET", "/v1/agents/muted");
2704
- if (!json)
2705
- console.log(chalk.dim(` [reactive] Listed muted agents`));
2706
- break;
2707
- }
2708
- case "list_project_commits": {
2709
- const pId = action.projectId;
2710
- if (!pId)
2711
- throw new Error("list_project_commits requires projectId");
2712
- const lpcqs = new URLSearchParams();
2713
- if (action.limit)
2714
- lpcqs.set("limit", String(action.limit));
2715
- if (action.offset)
2716
- lpcqs.set("offset", String(action.offset));
2717
- result = await runtime.connection.request("GET", `/v1/projects/${encodeURIComponent(pId)}/commits?${lpcqs}`);
2718
- if (!json)
2719
- console.log(chalk.dim(` [reactive] Listed commits for ${pId}`));
2720
- break;
2721
- }
2722
- case "list_projects": {
2723
- const lpqs = new URLSearchParams();
2724
- if (action.query)
2725
- lpqs.set("q", action.query);
2726
- if (action.limit)
2727
- lpqs.set("limit", String(action.limit));
2728
- result = await runtime.connection.request("GET", `/v1/search/projects?${lpqs}`);
2729
- if (!json)
2730
- console.log(chalk.dim(` [reactive] Listed projects`));
2731
- break;
2732
- }
2733
- case "list_proposals": {
2734
- const wId = action.workspaceId;
2735
- if (!wId)
2736
- throw new Error("list_proposals requires workspaceId");
2737
- const lppqs = new URLSearchParams();
2738
- if (action.status)
2739
- lppqs.set("status", action.status);
2740
- if (action.limit)
2741
- lppqs.set("limit", String(action.limit));
2742
- result = await runtime.connection.request("GET", `/v1/workspaces/${encodeURIComponent(wId)}/proposals?${lppqs}`);
2743
- if (!json)
2744
- console.log(chalk.dim(` [reactive] Listed proposals`));
2745
- break;
2746
- }
2747
- case "list_services": {
2748
- const lsqs = new URLSearchParams();
2749
- if (action.category)
2750
- lsqs.set("category", action.category);
2751
- if (action.limit)
2752
- lsqs.set("limit", String(action.limit));
2753
- result = await runtime.connection.request("GET", `/v1/index/services?${lsqs}`);
2754
- if (!json)
2755
- console.log(chalk.dim(` [reactive] Listed services`));
2756
- break;
2757
- }
2758
- case "list_swarms": {
2759
- const lswqs = new URLSearchParams();
2760
- if (action.mine)
2761
- lswqs.set("mine", "true");
2762
- if (action.status)
2763
- lswqs.set("status", action.status);
2764
- if (action.limit)
2765
- lswqs.set("limit", String(action.limit));
2766
- result = await runtime.connection.request("GET", `/v1/swarms?${lswqs}`);
2767
- if (!json)
2768
- console.log(chalk.dim(` [reactive] Listed swarms`));
2769
- break;
2770
- }
2771
- case "list_teaching_exchanges": {
2772
- const lteqs = new URLSearchParams();
2773
- if (action.role)
2774
- lteqs.set("role", action.role);
2775
- if (action.status)
2776
- lteqs.set("status", action.status);
2777
- if (action.limit)
2778
- lteqs.set("limit", String(action.limit));
2779
- result = await runtime.connection.request("GET", `/v1/teaching/exchanges?${lteqs}`);
2780
- if (!json)
2781
- console.log(chalk.dim(` [reactive] Listed teaching exchanges`));
2782
- break;
2783
- }
2784
- case "list_token_launches": {
2785
- const ltlqs = new URLSearchParams();
2786
- if (action.limit)
2787
- ltlqs.set("limit", String(action.limit));
2788
- if (action.offset)
2789
- ltlqs.set("offset", String(action.offset));
2790
- result = await runtime.connection.request("GET", `/v1/clawnch/launches?${ltlqs}`);
2791
- if (!json)
2792
- console.log(chalk.dim(` [reactive] Listed token launches`));
2793
- break;
2794
- }
2795
- case "list_workspaces": {
2796
- const lwqs = new URLSearchParams();
2797
- if (action.limit)
2798
- lwqs.set("limit", String(action.limit));
2799
- result = await runtime.connection.request("GET", `/v1/workspaces?${lwqs}`);
2800
- if (!json)
2801
- console.log(chalk.dim(` [reactive] Listed workspaces`));
2802
- break;
2803
- }
2804
- case "my_agreements": {
2805
- const maqs = new URLSearchParams();
2806
- if (action.role)
2807
- maqs.set("role", action.role);
2808
- if (action.status)
2809
- maqs.set("status", action.status);
2810
- if (action.limit)
2811
- maqs.set("limit", String(action.limit));
2812
- result = await runtime.connection.request("GET", `/v1/marketplace/agreements?${maqs}`);
2813
- if (!json)
2814
- console.log(chalk.dim(` [reactive] Got my agreements`));
2815
- break;
2816
- }
2817
- case "my_bounties": {
2818
- result = await runtime.connection.request("GET", "/v1/index/bounties?mine=true");
2819
- if (!json)
2820
- console.log(chalk.dim(` [reactive] Got my bounties`));
2821
- break;
2822
- }
2823
- case "my_skills": {
2824
- const addr3 = runtime.connection.address || "";
2825
- result = await runtime.connection.request("GET", `/v1/skills/registry?publisherId=${encodeURIComponent(addr3)}`);
2826
- if (!json)
2827
- console.log(chalk.dim(` [reactive] Got my skills`));
2828
- break;
2829
- }
2830
- case "my_tasks": {
2831
- result = await runtime.connection.request("GET", "/v1/swarms/subtasks?mine=true");
2832
- if (!json)
2833
- console.log(chalk.dim(` [reactive] Got my tasks`));
2834
- break;
2835
- }
2836
- case "available_subtasks": {
2837
- const asqs = new URLSearchParams();
2838
- if (action.skills)
2839
- asqs.set("skills", action.skills);
2840
- if (action.swarmId)
2841
- asqs.set("swarmId", action.swarmId);
2842
- if (action.limit)
2843
- asqs.set("limit", String(action.limit));
2844
- result = await runtime.connection.request("GET", `/v1/swarms/subtasks?${asqs}`);
2845
- if (!json)
2846
- console.log(chalk.dim(` [reactive] Listed available subtasks`));
2847
- break;
2848
- }
2849
- // ── Agent-first tools ──────────────────────────────────────
2850
- case "delegate_task": {
2851
- const dtTitle = action.title;
2852
- const dtDesc = action.description;
2853
- if (!dtTitle || !dtDesc)
2854
- throw new Error("delegate_task requires title and description");
2855
- result = await runtime.connection.request("POST", "/v1/swarms", {
2856
- title: dtTitle, description: dtDesc,
2857
- subtasks: [{ title: dtTitle, description: dtDesc, skillTags: action.skills || [] }],
2858
- });
2859
- if (!json)
2860
- console.log(chalk.dim(` [reactive] Delegated task: ${dtTitle}`));
2861
- break;
2862
- }
2863
- case "save_learning": {
2864
- const slTitle = action.title;
2865
- const slBody = action.body;
2866
- if (!slTitle || !slBody)
2867
- throw new Error("save_learning requires title and body");
2868
- result = await runtime.connection.request("POST", "/v1/agent-memory/store", {
2869
- type: "semantic", content: `${slTitle}: ${slBody}`,
2870
- importance: 0.7, tags: ["learning", ...(action.tags || [])],
2871
- source: "self",
2872
- });
2873
- if (!json)
2874
- console.log(chalk.dim(` [reactive] Saved learning: ${slTitle}`));
2875
- break;
2876
- }
2877
- case "recall": {
2878
- const recallQuery = action.query;
2879
- if (!recallQuery)
2880
- throw new Error("recall requires query");
2881
- result = await runtime.connection.request("POST", "/v1/agent-memory/recall", {
2882
- query: recallQuery, limit: action.limit || 10,
2883
- });
2884
- if (!json)
2885
- console.log(chalk.dim(` [reactive] Recalled memories`));
2886
- break;
2887
- }
2888
- case "save_checkpoint": {
2889
- const cpTask = action.task;
2890
- if (!cpTask)
2891
- throw new Error("save_checkpoint requires task");
2892
- const cpContent = `CHECKPOINT: ${cpTask} | Progress: ${action.progress || 0}% | Remaining: ${action.remaining || "unknown"} | Blockers: ${action.blockers || "none"} | Context: ${action.context || ""}`;
2893
- result = await runtime.connection.request("POST", "/v1/agent-memory/store", {
2894
- type: "episodic", content: cpContent, importance: 0.85,
2895
- tags: ["checkpoint", "work-state"], source: "self",
2896
- });
2897
- if (!json)
2898
- console.log(chalk.dim(` [reactive] Saved checkpoint: ${cpTask}`));
2899
- break;
2900
- }
2901
- case "resume_checkpoint": {
2902
- result = await runtime.connection.request("POST", "/v1/agent-memory/recall", {
2903
- query: "CHECKPOINT work state progress", type: "episodic", limit: 1,
2904
- });
2905
- if (!json)
2906
- console.log(chalk.dim(` [reactive] Resumed checkpoint`));
2907
- break;
2908
- }
2909
- case "request_review": {
2910
- const rvTitle = action.title;
2911
- const rvContent = action.content;
2912
- if (!rvTitle || !rvContent)
2913
- throw new Error("request_review requires title and content");
2914
- result = await runtime.connection.request("POST", "/v1/insights", {
2915
- title: rvTitle, body: rvContent,
2916
- strategyType: action.reviewType || "code",
2917
- tags: ["review-request", action.reviewType || "code"],
2918
- });
2919
- if (!json)
2920
- console.log(chalk.dim(` [reactive] Requested review: ${rvTitle}`));
2921
- break;
2922
- }
2923
- case "ask_network": {
2924
- const askQ = action.question;
2925
- if (!askQ)
2926
- throw new Error("ask_network requires question");
2927
- result = await runtime.connection.request("POST", "/v1/insights", {
2928
- title: `Question: ${askQ.slice(0, 80)}`, body: askQ,
2929
- strategyType: "question", tags: ["network-question"],
2930
- });
2931
- if (!json)
2932
- console.log(chalk.dim(` [reactive] Asked network`));
2933
- break;
2934
- }
2935
- case "check_delegation": {
2936
- const delBountyId = action.bountyId;
2937
- if (!delBountyId)
2938
- throw new Error("check_delegation requires bountyId");
2939
- result = await runtime.connection.request("GET", `/v1/swarms/${encodeURIComponent(delBountyId)}`);
2940
- if (!json)
2941
- console.log(chalk.dim(` [reactive] Checked delegation ${delBountyId}`));
2942
- break;
2943
- }
2944
- // ── On-chain tools missing from CLI ────────────────────────
2945
- case "post_content":
2946
- case "create_post": {
2947
- const postTitle = action.title;
2948
- const postBody = action.body;
2949
- if (!postTitle || !postBody)
2950
- throw new Error("post_content requires title and body");
2951
- result = await prepareSignRelay(runtime.connection, "/v1/prepare/post", {
2952
- title: postTitle, body: postBody,
2953
- tags: action.tags, community: action.community || "general",
2954
- });
2955
- if (!json)
2956
- console.log(chalk.dim(` [reactive] Published post: ${postTitle}`));
2957
- break;
2958
- }
2959
- case "comment_on_content": {
2960
- const parentCid = action.parentCid;
2961
- const commentBody = action.body;
2962
- if (!parentCid || !commentBody)
2963
- throw new Error("comment_on_content requires parentCid and body");
2964
- result = await prepareSignRelay(runtime.connection, "/v1/prepare/comment", {
2965
- parentCid, body: commentBody, community: action.community,
2966
- });
2967
- if (!json)
2968
- console.log(chalk.dim(` [reactive] Commented on ${parentCid.slice(0, 10)}...`));
2969
- break;
2970
- }
2971
- case "unfollow_agent": {
2972
- const unfAddr = (action.targetAddress || target);
2973
- if (!unfAddr)
2974
- throw new Error("unfollow_agent requires targetAddress");
2975
- result = await prepareSignRelay(runtime.connection, "/v1/prepare/unfollow", { address: unfAddr });
2976
- if (!json)
2977
- console.log(chalk.dim(` [reactive] Unfollowed ${unfAddr.slice(0, 10)}...`));
2978
- break;
2979
- }
2980
- case "approve_bounty_applicant": {
2981
- const abId = (action.bountyId || action.id);
2982
- const applicantAddr = action.applicantAddress;
2983
- if (!abId || !applicantAddr)
2984
- throw new Error("approve_bounty_applicant requires bountyId and applicantAddress");
2985
- result = await prepareSignRelay(runtime.connection, `/v1/prepare/bounty/${encodeURIComponent(abId)}/approve-claimer`, { applicantAddress: applicantAddr });
2986
- if (!json)
2987
- console.log(chalk.dim(` [reactive] Approved bounty applicant ${applicantAddr.slice(0, 10)}...`));
2988
- break;
2989
- }
2990
- case "create_service_listing": {
2991
- const slsTitle = action.title;
2992
- const slsDesc = action.description;
2993
- const slsCat = action.category;
2994
- if (!slsTitle || !slsDesc || !slsCat)
2995
- throw new Error("create_service_listing requires title, description, category");
2996
- result = await prepareSignRelay(runtime.connection, "/v1/prepare/service/list", {
2997
- title: slsTitle, description: slsDesc, category: slsCat,
2998
- priceAmount: action.priceAmount, pricingModel: action.pricingModel,
2999
- tags: action.tags, tokenAddress: action.tokenAddress,
3000
- });
3001
- if (!json)
3002
- console.log(chalk.dim(` [reactive] Created service listing: ${slsTitle}`));
3003
- break;
3004
- }
3005
- case "hire_agent": {
3006
- const listingId2 = action.listingId;
3007
- const requirements = action.requirements;
3008
- if (!listingId2 || !requirements)
3009
- throw new Error("hire_agent requires listingId and requirements");
3010
- result = await prepareSignRelay(runtime.connection, "/v1/prepare/service/agree", {
3011
- listingId: listingId2, requirements, budget: action.budget,
3012
- tokenAddress: action.tokenAddress,
3013
- });
3014
- if (!json)
3015
- console.log(chalk.dim(` [reactive] Hired agent via listing ${listingId2}`));
3016
- break;
3017
- }
3018
- case "accept_service": {
3019
- const agreeId = action.agreementId;
3020
- if (!agreeId)
3021
- throw new Error("accept_service requires agreementId");
3022
- result = await runtime.connection.request("POST", `/v1/marketplace/agreements/${encodeURIComponent(agreeId)}/accept`, {});
3023
- if (!json)
3024
- console.log(chalk.dim(` [reactive] Accepted service agreement ${agreeId}`));
3025
- break;
3026
- }
3027
- case "dispute_service": {
3028
- const dAgreeId = action.agreementId;
3029
- if (!dAgreeId)
3030
- throw new Error("dispute_service requires agreementId");
3031
- result = await prepareSignRelay(runtime.connection, "/v1/prepare/service/dispute", {
3032
- agreementId: dAgreeId, reason: action.reason,
3033
- });
3034
- if (!json)
3035
- console.log(chalk.dim(` [reactive] Disputed service ${dAgreeId}`));
3036
- break;
3037
- }
3038
- case "cancel_service": {
3039
- const cAgreeId = action.agreementId;
3040
- if (!cAgreeId)
3041
- throw new Error("cancel_service requires agreementId");
3042
- result = await prepareSignRelay(runtime.connection, "/v1/prepare/service/cancel", { agreementId: cAgreeId });
3043
- if (!json)
3044
- console.log(chalk.dim(` [reactive] Cancelled service ${cAgreeId}`));
3045
- break;
3046
- }
3047
- case "approve_token": {
3048
- const tokenAddr2 = action.tokenAddress;
3049
- const spenderAddr2 = action.spenderAddress;
3050
- const amount = action.amount || "max";
3051
- if (!tokenAddr2 || !spenderAddr2)
3052
- throw new Error("approve_token requires tokenAddress and spenderAddress");
3053
- result = await runtime.connection.request("POST", "/v1/token/approve", {
3054
- tokenAddress: tokenAddr2, spenderAddress: spenderAddr2, amount,
3055
- });
3056
- if (!json)
3057
- console.log(chalk.dim(` [reactive] Approved token spending`));
3058
- break;
3059
- }
3060
- // ── Proactive/signal tools ─────────────────────────────────
3061
- case "poll_signals": {
3062
- const psqs = new URLSearchParams();
3063
- if (action.limit)
3064
- psqs.set("limit", String(action.limit));
3065
- result = await runtime.connection.request("GET", `/v1/proactive/pending-signals?${psqs}`);
3066
- if (!json)
3067
- console.log(chalk.dim(` [reactive] Polled signals`));
3068
- break;
3069
- }
3070
- case "ack_signal": {
3071
- const sigId = action.signalId;
3072
- if (!sigId)
3073
- throw new Error("ack_signal requires signalId");
3074
- result = await runtime.connection.request("POST", `/v1/proactive/signals/${encodeURIComponent(sigId)}/ack`, {});
3075
- if (!json)
3076
- console.log(chalk.dim(` [reactive] Acknowledged signal ${sigId}`));
3077
- break;
3078
- }
3079
- case "approve_action": {
3080
- const actId = action.actionId;
3081
- if (!actId)
3082
- throw new Error("approve_action requires actionId");
3083
- result = await runtime.connection.request("POST", `/v1/proactive/approvals/${encodeURIComponent(actId)}/approve`, {});
3084
- if (!json)
3085
- console.log(chalk.dim(` [reactive] Approved action ${actId}`));
3086
- break;
3087
- }
3088
- case "reject_action": {
3089
- const rejActId = action.actionId;
3090
- if (!rejActId)
3091
- throw new Error("reject_action requires actionId");
3092
- result = await runtime.connection.request("POST", `/v1/proactive/approvals/${encodeURIComponent(rejActId)}/reject`, { reason: action.reason });
3093
- if (!json)
3094
- console.log(chalk.dim(` [reactive] Rejected action ${rejActId}`));
3095
- break;
3096
- }
3097
- case "configure_proactive": {
3098
- result = await runtime.connection.request("PUT", "/v1/proactive/settings", {
3099
- enabled: action.enabled, scanIntervalMinutes: action.scanIntervalMinutes,
3100
- maxActionsPerDay: action.maxActionsPerDay, callbackFormat: action.callbackFormat,
3101
- });
3102
- if (!json)
3103
- console.log(chalk.dim(` [reactive] Configured proactive settings`));
3104
- break;
3105
- }
3106
- // ── Content/write tools ────────────────────────────────────
3107
- case "send_channel_message": {
3108
- const chId = action.channelId;
3109
- const chContent = action.content;
3110
- if (!chId || !chContent)
3111
- throw new Error("send_channel_message requires channelId and content");
3112
- try {
3113
- await runtime.connection.request("POST", `/v1/channels/${encodeURIComponent(chId)}/join`, {});
3114
- }
3115
- catch { }
3116
- result = await runtime.connection.request("POST", `/v1/channels/${encodeURIComponent(chId)}/messages`, { content: chContent });
3117
- if (!json)
3118
- console.log(chalk.dim(` [reactive] Sent channel message`));
3119
- break;
3120
- }
3121
- case "read_channel_messages": {
3122
- const rcmChId = action.channelId;
3123
- if (!rcmChId)
3124
- throw new Error("read_channel_messages requires channelId");
3125
- const rcmqs = new URLSearchParams();
3126
- if (action.limit)
3127
- rcmqs.set("limit", String(action.limit));
3128
- if (action.before)
3129
- rcmqs.set("before", action.before);
3130
- result = await runtime.connection.request("GET", `/v1/channels/${encodeURIComponent(rcmChId)}/messages?${rcmqs}`);
3131
- if (!json)
3132
- console.log(chalk.dim(` [reactive] Read channel messages`));
3133
- break;
3134
- }
3135
- case "subscribe":
3136
- case "create_search_subscription": {
3137
- const subLabel = action.label;
3138
- const subQuery = action.query;
3139
- if (!subLabel || !subQuery)
3140
- throw new Error("subscribe requires label and query");
3141
- result = await runtime.connection.request("POST", "/v1/search/subscriptions", {
3142
- label: subLabel, query: subQuery,
3143
- types: action.types, frequencyMinutes: action.frequencyMinutes,
3144
- });
3145
- if (!json)
3146
- console.log(chalk.dim(` [reactive] Created subscription: ${subLabel}`));
3147
- break;
3148
- }
3149
- case "mute_agent": {
3150
- const muteAddr = (action.address || target);
3151
- if (!muteAddr)
3152
- throw new Error("mute_agent requires address");
3153
- result = await runtime.connection.request("POST", `/v1/agents/${encodeURIComponent(muteAddr)}/mute`, {});
3154
- if (!json)
3155
- console.log(chalk.dim(` [reactive] Muted ${muteAddr.slice(0, 10)}...`));
3156
- break;
3157
- }
3158
- case "unmute_agent": {
3159
- const unmuteAddr = (action.address || target);
3160
- if (!unmuteAddr)
3161
- throw new Error("unmute_agent requires address");
3162
- result = await runtime.connection.request("DELETE", `/v1/agents/${encodeURIComponent(unmuteAddr)}/mute`);
3163
- if (!json)
3164
- console.log(chalk.dim(` [reactive] Unmuted ${unmuteAddr.slice(0, 10)}...`));
3165
- break;
3166
- }
3167
- case "report_spam":
3168
- case "report_content": {
3169
- const reportCid = (action.contentCid || action.cid);
3170
- const reportReason = action.reason;
3171
- if (!reportCid || !reportReason)
3172
- throw new Error("report_content requires cid and reason");
3173
- result = await runtime.connection.request("POST", `/v1/content/${encodeURIComponent(reportCid)}/report`, { reason: reportReason, details: action.details });
3174
- if (!json)
3175
- console.log(chalk.dim(` [reactive] Reported content ${reportCid.slice(0, 10)}...`));
3176
- break;
3177
- }
3178
- case "import_project_url": {
3179
- const impProjId = action.projectId;
3180
- const impUrl = action.url;
3181
- if (!impProjId || !impUrl)
3182
- throw new Error("import_project_url requires projectId and url");
3183
- result = await runtime.connection.request("POST", `/v1/projects/${encodeURIComponent(impProjId)}/import-url`, {
3184
- url: impUrl, branch: action.branch, subdir: action.subdir,
3185
- });
3186
- if (!json)
3187
- console.log(chalk.dim(` [reactive] Imported from ${impUrl}`));
3188
- break;
3189
- }
3190
- case "match_submission_spec": {
3191
- const msBountyId = action.bountyId;
3192
- const msSubId = action.subId;
3193
- if (!msBountyId || !msSubId)
3194
- throw new Error("match_submission_spec requires bountyId and subId");
3195
- result = await runtime.connection.request("POST", `/v1/bounties/${encodeURIComponent(msBountyId)}/submissions/${encodeURIComponent(msSubId)}/match-spec`, {});
3196
- if (!json)
3197
- console.log(chalk.dim(` [reactive] Matched submission spec`));
3198
- break;
3199
- }
3200
- case "verify_submission": {
3201
- const vsBountyId = action.bountyId;
3202
- const vsSubId = action.subId;
3203
- if (!vsBountyId || !vsSubId)
3204
- throw new Error("verify_submission requires bountyId and subId");
3205
- result = await runtime.connection.request("POST", `/v1/bounties/${encodeURIComponent(vsBountyId)}/submissions/${encodeURIComponent(vsSubId)}/verify`, { testCommand: action.testCommand });
3206
- if (!json)
3207
- console.log(chalk.dim(` [reactive] Verified submission`));
3208
- break;
3209
- }
3210
- case "review_submission": {
3211
- const rsBountyId = action.bountyId;
3212
- const rsSubId = action.subId;
3213
- if (!rsBountyId || !rsSubId)
3214
- throw new Error("review_submission requires bountyId and subId");
3215
- result = await runtime.connection.request("POST", `/v1/bounties/${encodeURIComponent(rsBountyId)}/submissions/${encodeURIComponent(rsSubId)}/review`, {});
3216
- if (!json)
3217
- console.log(chalk.dim(` [reactive] Reviewed submission`));
3218
- break;
3219
- }
3220
- case "review_merge_request": {
3221
- const rmrProjId = action.projectId;
3222
- const rmrMrId = action.mrId;
3223
- if (!rmrProjId || !rmrMrId)
3224
- throw new Error("review_merge_request requires projectId and mrId");
3225
- const mr = await runtime.connection.request("GET", `/v1/projects/${encodeURIComponent(rmrProjId)}/merge-requests/${encodeURIComponent(rmrMrId)}`);
3226
- const commits = (mr?.commits || []);
3227
- const reviews = [];
3228
- for (const c of commits) {
3229
- try {
3230
- const rv = await runtime.connection.request("POST", `/v1/projects/${encodeURIComponent(rmrProjId)}/commits/${encodeURIComponent(c.id || c.commitId)}/ai-review`, {});
3231
- reviews.push(rv);
3232
- }
3233
- catch { }
3234
- }
3235
- result = { mergeRequest: mr, reviews };
3236
- if (!json)
3237
- console.log(chalk.dim(` [reactive] Reviewed MR ${rmrMrId} (${reviews.length} commits)`));
3238
- break;
3239
- }
3240
- case "update_profile": {
3241
- result = await runtime.connection.request("PATCH", "/v1/agents/me", {
3242
- displayName: action.displayName, description: action.description,
3243
- capabilities: action.capabilities,
3244
- });
3245
- if (!json)
3246
- console.log(chalk.dim(` [reactive] Updated profile`));
3247
- break;
3248
- }
3249
- case "register": {
3250
- result = await runtime.connection.request("POST", "/v1/agents/register", {
3251
- name: action.name, description: action.description,
3252
- });
3253
- if (!json)
3254
- console.log(chalk.dim(` [reactive] Registered agent`));
3255
- break;
3256
- }
3257
- // ── Workspace tools ────────────────────────────────────────
3258
- case "create_workspace": {
3259
- const cwName = action.name;
3260
- if (!cwName)
3261
- throw new Error("create_workspace requires name");
3262
- result = await runtime.connection.request("POST", "/v1/workspaces", { name: cwName, description: action.description });
3263
- if (!json)
3264
- console.log(chalk.dim(` [reactive] Created workspace: ${cwName}`));
3265
- break;
3266
- }
3267
- case "workspace_add_member": {
3268
- const wamWsId = action.workspaceId;
3269
- const wamAgentId = action.agentId;
3270
- if (!wamWsId || !wamAgentId)
3271
- throw new Error("workspace_add_member requires workspaceId and agentId");
3272
- result = await runtime.connection.request("POST", `/v1/workspaces/${encodeURIComponent(wamWsId)}/members`, { agentId: wamAgentId, role: action.role || "editor" });
3273
- if (!json)
3274
- console.log(chalk.dim(` [reactive] Added member to workspace`));
3275
- break;
3276
- }
3277
- case "workspace_set_entry": {
3278
- const wseWsId = action.workspaceId;
3279
- const wseKey = action.key;
3280
- if (!wseWsId || !wseKey)
3281
- throw new Error("workspace_set_entry requires workspaceId and key");
3282
- result = await runtime.connection.request("PUT", `/v1/workspaces/${encodeURIComponent(wseWsId)}/state`, { key: wseKey, value: action.value });
3283
- if (!json)
3284
- console.log(chalk.dim(` [reactive] Set workspace entry: ${wseKey}`));
3285
- break;
3286
- }
3287
- case "workspace_get_entries": {
3288
- const wgeWsId = action.workspaceId;
3289
- if (!wgeWsId)
3290
- throw new Error("workspace_get_entries requires workspaceId");
3291
- result = await runtime.connection.request("GET", `/v1/workspaces/${encodeURIComponent(wgeWsId)}/state`);
3292
- if (!json)
3293
- console.log(chalk.dim(` [reactive] Got workspace entries`));
3294
- break;
3295
- }
3296
- case "create_proposal": {
3297
- const cpWsId = action.workspaceId;
3298
- const cpTitle = action.title;
3299
- if (!cpWsId || !cpTitle)
3300
- throw new Error("create_proposal requires workspaceId and title");
3301
- result = await runtime.connection.request("POST", `/v1/workspaces/${encodeURIComponent(cpWsId)}/proposals`, {
3302
- title: cpTitle, description: action.description,
3303
- actionType: action.actionType, actionPayload: action.actionPayload,
3304
- });
3305
- if (!json)
3306
- console.log(chalk.dim(` [reactive] Created proposal: ${cpTitle}`));
3307
- break;
3308
- }
3309
- // ── Skill/rating tools ─────────────────────────────────────
3310
- case "rate_skill":
3311
- case "review_skill": {
3312
- const rsSkillId = action.skillId;
3313
- const rsRating = action.rating;
3314
- if (!rsSkillId || !rsRating)
3315
- throw new Error("rate_skill requires skillId and rating");
3316
- result = await runtime.connection.request("POST", `/v1/skills/registry/${encodeURIComponent(rsSkillId)}/review`, {
3317
- rating: rsRating, review: action.review,
3318
- });
3319
- if (!json)
3320
- console.log(chalk.dim(` [reactive] Rated skill ${rsSkillId}`));
3321
- break;
3322
- }
3323
- case "teaching_stats": {
3324
- result = await runtime.connection.request("GET", "/v1/teaching/stats");
3325
- if (!json)
3326
- console.log(chalk.dim(` [reactive] Got teaching stats`));
3327
- break;
3328
- }
3329
- case "search_teachers": {
3330
- const stGoal = action.goal;
3331
- if (!stGoal)
3332
- throw new Error("search_teachers requires goal");
3333
- const stqs = new URLSearchParams();
3334
- stqs.set("goal", stGoal);
3335
- if (action.limit)
3336
- stqs.set("limit", String(action.limit));
3337
- result = await runtime.connection.request("GET", `/v1/teaching/search-teachers?${stqs}`);
3338
- if (!json)
3339
- console.log(chalk.dim(` [reactive] Searched teachers`));
3340
- break;
3341
- }
3342
- // ── Token launch tools ─────────────────────────────────────
3343
- case "report_token_launch": {
3344
- const tokenName = action.tokenName;
3345
- const tokenTicker = action.tokenTicker;
3346
- const tokenAddress2 = action.tokenAddress;
3347
- if (!tokenName || !tokenTicker || !tokenAddress2)
3348
- throw new Error("report_token_launch requires tokenName, tokenTicker, tokenAddress");
3349
- result = await runtime.connection.request("POST", "/v1/clawnch/report-launch", {
3350
- tokenName, tokenTicker, tokenAddress: tokenAddress2,
3351
- description: action.description, imageUrl: action.imageUrl,
3352
- poolAddress: action.poolAddress, protocolFeeSharePct: action.protocolFeeSharePct,
3353
- });
3354
- if (!json)
3355
- console.log(chalk.dim(` [reactive] Reported token launch: ${tokenName}`));
3356
- break;
3357
- }
3358
- case "ignore":
3359
- break;
3360
- default: {
3361
- // ── Unhandled action ─────────────────────────────────────
3362
- // All known tools should have explicit cases above.
3363
- // Log unhandled for debugging — DO NOT route through MCP.
3364
- if (!json)
3365
- console.log(chalk.dim(` [reactive] Unhandled action: ${action.action}`));
3366
- break;
3367
- }
433
+ // ── Unified dispatch via POST /v1/actions/execute ──
434
+ if (action.action === "ignore") {
435
+ return;
436
+ }
437
+ // Intercept browse_tools (client-side, no gateway call needed)
438
+ if (action.action === "browse_tools") {
439
+ const category = action.category;
440
+ if (!category) {
441
+ const listing = getCategoryListing();
442
+ console.log(`[browse_tools] Categories: ${listing.map((c) => `${c.name} (${c.count})`).join(", ")}`);
443
+ return;
444
+ }
445
+ loadedCategories.add(category);
446
+ const tools = getToolsInCategory(category);
447
+ console.log(`[browse_tools] Loaded ${tools.length} tools from "${category}"`);
448
+ return;
449
+ }
450
+ const toolName = `nookplot_${action.action}`;
451
+ const payload = { ...action };
452
+ delete payload.action;
453
+ if (target && !payload.to)
454
+ payload.to = target;
455
+ if (content && !payload.content)
456
+ payload.content = content;
457
+ if (channelId && !payload.channelId)
458
+ payload.channelId = channelId;
459
+ const dispatchResult = await runtime.connection.request("POST", "/v1/actions/execute", { toolName, payload });
460
+ switch (dispatchResult.status) {
461
+ case "completed":
462
+ break;
463
+ case "sign_required": {
464
+ if (!dispatchResult.forwardRequest || !dispatchResult.domain || !dispatchResult.types) {
465
+ throw new Error(`sign_required response missing forwardRequest/domain/types for ${action.action}`);
466
+ }
467
+ const { signForwardRequest } = await import("@nookplot/runtime");
468
+ const privateKey = runtime.connection.privateKey;
469
+ if (!privateKey)
470
+ throw new Error("Private key not configured — cannot sign on-chain transactions.");
471
+ const signature = await signForwardRequest(privateKey, dispatchResult.domain, dispatchResult.types, dispatchResult.forwardRequest);
472
+ const relayResult = await runtime.connection.request("POST", "/v1/relay", { ...dispatchResult.forwardRequest, signature });
473
+ if (!json)
474
+ console.log(chalk.dim(` [reactive] On-chain tx: ${relayResult.txHash}`));
475
+ break;
476
+ }
477
+ case "client_side_required":
478
+ if (!json)
479
+ console.log(chalk.dim(` [reactive] Client-side action required: ${dispatchResult.action}`));
480
+ break;
481
+ case "error":
482
+ throw new Error(dispatchResult.error ?? `Action failed: ${action.action}`);
483
+ default:
484
+ if (!json)
485
+ console.log(chalk.dim(` [reactive] Unexpected dispatch status: ${dispatchResult.status}`));
3368
486
  }
3369
487
  if (!json && action.action !== "ignore") {
3370
488
  console.log(chalk.green(` [reactive] ✓ ${action.action}${target ? ` → ${target.slice(0, 10)}...` : ""}`));