@sage-protocol/cli 0.3.10 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/browser-wallet-integration.js +0 -1
- package/dist/cli/cast-wallet-manager.js +0 -1
- package/dist/cli/commands/interview.js +149 -0
- package/dist/cli/commands/personal.js +234 -89
- package/dist/cli/commands/stake-status.js +0 -2
- package/dist/cli/config.js +28 -8
- package/dist/cli/governance-manager.js +28 -19
- package/dist/cli/index.js +32 -8
- package/dist/cli/library-manager.js +16 -6
- package/dist/cli/mcp-server-stdio.js +549 -0
- package/dist/cli/mcp-server.js +4 -30
- package/dist/cli/mcp-setup.md +35 -34
- package/dist/cli/metamask-integration.js +0 -1
- package/dist/cli/privy-wallet-manager.js +2 -2
- package/dist/cli/prompt-manager.js +0 -1
- package/dist/cli/services/doctor/fixers.js +1 -1
- package/dist/cli/services/mcp/env-loader.js +2 -0
- package/dist/cli/services/mcp/quick-start.js +14 -15
- package/dist/cli/services/mcp/sage-tool-registry.js +330 -0
- package/dist/cli/services/mcp/tool-args-validator.js +31 -0
- package/dist/cli/services/metaprompt/anthropic-client.js +87 -0
- package/dist/cli/services/metaprompt/interview-driver.js +161 -0
- package/dist/cli/services/metaprompt/model-client.js +49 -0
- package/dist/cli/services/metaprompt/openai-client.js +67 -0
- package/dist/cli/services/metaprompt/persistence.js +86 -0
- package/dist/cli/services/metaprompt/prompt-builder.js +186 -0
- package/dist/cli/services/metaprompt/session.js +18 -80
- package/dist/cli/services/metaprompt/slot-planner.js +115 -0
- package/dist/cli/services/metaprompt/templates.json +130 -0
- package/dist/cli/subdao.js +0 -3
- package/dist/cli/sxxx-manager.js +0 -1
- package/dist/cli/utils/tx-wait.js +0 -3
- package/dist/cli/wallet-manager.js +18 -19
- package/dist/cli/walletconnect-integration.js +0 -1
- package/dist/cli/wizard-manager.js +0 -1
- package/package.json +3 -1
package/dist/cli/mcp-setup.md
CHANGED
|
@@ -18,10 +18,10 @@ Create or update your `.env` file with the required configuration:
|
|
|
18
18
|
|
|
19
19
|
```bash
|
|
20
20
|
# Subgraph (preferred) + Blockchain
|
|
21
|
-
SUBGRAPH_URL=https://api.goldsky.com/api/public/project_cmhxp0fppsbdd01q56xp2gqw9/subgraphs/sxxx-protocol/1.0.
|
|
22
|
-
RPC_URL=https://sepolia.
|
|
23
|
-
LIBRARY_REGISTRY_ADDRESS=
|
|
24
|
-
SUBDAO_FACTORY_ADDRESS=
|
|
21
|
+
SUBGRAPH_URL=https://api.goldsky.com/api/public/project_cmhxp0fppsbdd01q56xp2gqw9/subgraphs/sxxx-protocol/1.0.2/gn
|
|
22
|
+
RPC_URL=https://base-sepolia.publicnode.com
|
|
23
|
+
LIBRARY_REGISTRY_ADDRESS=0x419Cd79d58db6A5aE1900dd7F0c1b8d153FfaD06
|
|
24
|
+
SUBDAO_FACTORY_ADDRESS=0xED573E7e4c00fE325f846B961Df3352807eA3807
|
|
25
25
|
|
|
26
26
|
# Optional: Custom IPFS Gateway
|
|
27
27
|
IPFS_GATEWAY=https://ipfs.io/ipfs
|
|
@@ -65,10 +65,10 @@ You should see a JSON response listing the available tools.
|
|
|
65
65
|
"command": "node",
|
|
66
66
|
"args": ["/absolute/path/to/sage-protocol/cli/mcp-server-stdio.js"],
|
|
67
67
|
"env": {
|
|
68
|
-
"SUBGRAPH_URL": "https://api.goldsky.com/api/public/project_cmhxp0fppsbdd01q56xp2gqw9/subgraphs/sxxx-protocol/1.0.
|
|
69
|
-
"RPC_URL": "https://sepolia.
|
|
70
|
-
"LIBRARY_REGISTRY_ADDRESS": "
|
|
71
|
-
"SUBDAO_FACTORY_ADDRESS": "
|
|
68
|
+
"SUBGRAPH_URL": "https://api.goldsky.com/api/public/project_cmhxp0fppsbdd01q56xp2gqw9/subgraphs/sxxx-protocol/1.0.2/gn",
|
|
69
|
+
"RPC_URL": "https://base-sepolia.publicnode.com",
|
|
70
|
+
"LIBRARY_REGISTRY_ADDRESS": "0x419Cd79d58db6A5aE1900dd7F0c1b8d153FfaD06",
|
|
71
|
+
"SUBDAO_FACTORY_ADDRESS": "0xED573E7e4c00fE325f846B961Df3352807eA3807"
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
74
|
}
|
|
@@ -97,36 +97,37 @@ Can you search for on-chain prompts related to "real estate"?
|
|
|
97
97
|
or
|
|
98
98
|
|
|
99
99
|
```
|
|
100
|
-
Please list all available
|
|
100
|
+
Please list all available DAOs in the Sage Protocol.
|
|
101
101
|
```
|
|
102
102
|
|
|
103
103
|
## Available MCP Tools
|
|
104
104
|
|
|
105
|
-
Your Sage Protocol MCP Server provides these tools
|
|
106
|
-
|
|
107
|
-
###
|
|
108
|
-
-
|
|
109
|
-
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
-
|
|
118
|
-
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
-
|
|
123
|
-
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
###
|
|
127
|
-
-
|
|
128
|
-
-
|
|
129
|
-
|
|
105
|
+
Your Sage Protocol MCP Server provides these tools. For the full list, see `docs/development/mcp-config.md`.
|
|
106
|
+
|
|
107
|
+
### Quick Workflow (recommended)
|
|
108
|
+
- `quick_create_prompt` - Create a new prompt (handles library creation automatically)
|
|
109
|
+
- `quick_iterate_prompt` - Update an existing prompt with automatic backup
|
|
110
|
+
- `quick_test_prompt` / `test_prompt` - Test a prompt with variable substitution
|
|
111
|
+
- `improve_prompt` - Analyze a prompt and suggest improvements
|
|
112
|
+
- `rename_prompt` - Rename a prompt's key/display name
|
|
113
|
+
- `help` - Get help on Sage MCP workflows
|
|
114
|
+
|
|
115
|
+
### Discovery & Search
|
|
116
|
+
- `search_prompts` - Unified search across local and on-chain sources
|
|
117
|
+
- `search_onchain_prompts` - Search directly from on-chain registries
|
|
118
|
+
- `trending_prompts` - List trending prompts
|
|
119
|
+
- `list_prompts` - List prompts from local libraries
|
|
120
|
+
- `get_prompt` - Retrieve a specific prompt by key
|
|
121
|
+
- `get_prompt_content` - Fetch full content from IPFS by CID
|
|
122
|
+
- `list_libraries` - Page through libraries (local or on-chain)
|
|
123
|
+
- `list_subdaos` - List all available DAOs
|
|
124
|
+
- `get_library_manifests` - Get executed library manifests
|
|
125
|
+
|
|
126
|
+
### Publishing & Governance
|
|
127
|
+
- `suggest_subdaos_for_library` - Recommend DAOs for publishing
|
|
128
|
+
- `generate_publishing_commands` - Generate CLI commands to publish
|
|
129
|
+
- `publish_manifest_flow` - Validate → Push → Proposal payload (no signing)
|
|
130
|
+
- `list_proposals` - List active proposals for a DAO
|
|
130
131
|
|
|
131
132
|
## Troubleshooting
|
|
132
133
|
|
|
@@ -142,7 +142,7 @@ class PrivyWalletManager {
|
|
|
142
142
|
|
|
143
143
|
async initialize() {
|
|
144
144
|
try {
|
|
145
|
-
console.log('✅ Deterministic wallet manager initialized');
|
|
145
|
+
if (process.env.SAGE_VERBOSE === '1') console.log('✅ Deterministic wallet manager initialized');
|
|
146
146
|
return true;
|
|
147
147
|
} catch (error) {
|
|
148
148
|
console.error('❌ Wallet initialization failed:', error.message);
|
|
@@ -208,7 +208,7 @@ class PrivyWalletManager {
|
|
|
208
208
|
async promptEmail() {
|
|
209
209
|
let cached = getCachedPrivyEmail();
|
|
210
210
|
if (cached && cached.includes('@')) {
|
|
211
|
-
if (!process.env.SAGE_QUIET_JSON) console.log(`📧 Using cached Privy email: ${cached}`);
|
|
211
|
+
if (!process.env.SAGE_QUIET_JSON && process.env.SAGE_VERBOSE === '1') console.log(`📧 Using cached Privy email: ${cached}`);
|
|
212
212
|
return cached;
|
|
213
213
|
}
|
|
214
214
|
let email = '';
|
|
@@ -92,7 +92,7 @@ async function fixIpfsKeys(context = {}) {
|
|
|
92
92
|
if (!envContent.includes('PINATA_SECRET_API_KEY=')) envContent += `\nPINATA_SECRET_API_KEY=${answers.secret}`;
|
|
93
93
|
if (answers.jwt && !envContent.includes('PINATA_JWT=')) envContent += `\nPINATA_JWT=${answers.jwt}`;
|
|
94
94
|
fs.writeFileSync(envPath, envContent);
|
|
95
|
-
try {
|
|
95
|
+
try { config.loadEnv(); } catch(_){}
|
|
96
96
|
console.log('✅ Added Pinata keys to .env');
|
|
97
97
|
}
|
|
98
98
|
}
|
|
@@ -55,6 +55,8 @@ function hydrateEnvFromSageConfig(options = {}) {
|
|
|
55
55
|
SUBDAO_FACTORY_ADDRESS: addresses.SUBDAO_FACTORY_ADDRESS || addresses.SUBDAO_FACTORY,
|
|
56
56
|
LIBRARY_REGISTRY_ADDRESS: addresses.LIBRARY_REGISTRY_ADDRESS || addresses.LIBRARY_REGISTRY,
|
|
57
57
|
SXXX_TOKEN_ADDRESS: addresses.SXXX_TOKEN_ADDRESS || addresses.SXXX,
|
|
58
|
+
SUBGRAPH_URL: addresses.SAGE_SUBGRAPH_URL || addresses.SUBGRAPH_URL,
|
|
59
|
+
SAGE_SUBGRAPH_URL: addresses.SAGE_SUBGRAPH_URL,
|
|
58
60
|
};
|
|
59
61
|
for (const [key, value] of Object.entries(mapping)) {
|
|
60
62
|
if (value && typeof value === 'string' && !process.env[key]) {
|
|
@@ -60,13 +60,12 @@ function createQuickStart({
|
|
|
60
60
|
// Since LibraryManager doesn't expose "addPrompt", we'll implement it here for now
|
|
61
61
|
// In a real refactor, we should move this to LibraryManager
|
|
62
62
|
|
|
63
|
-
const libDir = libraryManager.ensureLibrariesDir();
|
|
64
|
-
const manifestPath = path.join(libDir, `${targetLib.cid}.json`);
|
|
65
|
-
|
|
66
63
|
// Create prompt file
|
|
67
64
|
// We'll store it in a 'prompts' subdirectory next to the manifest if possible,
|
|
68
65
|
// but for local libraries, they are flat in ~/.sage/libraries/
|
|
69
66
|
// Let's create a prompts directory inside ~/.sage/libraries/prompts/
|
|
67
|
+
const libDir = libraryManager.ensureLibrariesDir();
|
|
68
|
+
const manifestPath = libraryManager.getManifestPath(targetLib.cid);
|
|
70
69
|
const promptsDir = path.join(libDir, 'prompts');
|
|
71
70
|
if (!fs.existsSync(promptsDir)) {
|
|
72
71
|
fs.mkdirSync(promptsDir, { recursive: true });
|
|
@@ -114,7 +113,7 @@ function createQuickStart({
|
|
|
114
113
|
cid: '' // Local prompt
|
|
115
114
|
});
|
|
116
115
|
|
|
117
|
-
|
|
116
|
+
libraryManager.writeManifest(targetLib.cid, manifest);
|
|
118
117
|
|
|
119
118
|
return {
|
|
120
119
|
success: true,
|
|
@@ -129,19 +128,18 @@ function createQuickStart({
|
|
|
129
128
|
if (!key) throw new Error('Key is required');
|
|
130
129
|
|
|
131
130
|
// Find the prompt
|
|
132
|
-
|
|
131
|
+
const pinned = libraryManager.listPinned();
|
|
133
132
|
let found = null;
|
|
134
133
|
let foundLib = null;
|
|
135
134
|
|
|
136
135
|
for (const lib of pinned) {
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
}
|
|
136
|
+
const { manifest } = libraryManager.loadPinned(lib.cid);
|
|
137
|
+
const prompt = manifest.prompts?.find(p => p.key === key);
|
|
138
|
+
if (prompt) {
|
|
139
|
+
found = prompt;
|
|
140
|
+
foundLib = { ...lib, manifest };
|
|
141
|
+
break;
|
|
142
|
+
}
|
|
145
143
|
}
|
|
146
144
|
|
|
147
145
|
if (!found) {
|
|
@@ -150,13 +148,13 @@ function createQuickStart({
|
|
|
150
148
|
|
|
151
149
|
// Update content if provided
|
|
152
150
|
if (content) {
|
|
153
|
-
const libDir = libraryManager.ensureLibrariesDir();
|
|
154
151
|
let promptFilePath;
|
|
155
152
|
|
|
156
153
|
if (found.files && found.files.length > 0) {
|
|
157
154
|
// Use existing file
|
|
158
155
|
const relativePath = found.files[0];
|
|
159
156
|
// Handle potential path issues
|
|
157
|
+
const libDir = libraryManager.ensureLibrariesDir();
|
|
160
158
|
promptFilePath = path.join(libDir, relativePath);
|
|
161
159
|
|
|
162
160
|
// Backup existing
|
|
@@ -166,6 +164,7 @@ function createQuickStart({
|
|
|
166
164
|
}
|
|
167
165
|
} else {
|
|
168
166
|
// Create new file if none existed (legacy/imported)
|
|
167
|
+
const libDir = libraryManager.ensureLibrariesDir();
|
|
169
168
|
const promptsDir = path.join(libDir, 'prompts');
|
|
170
169
|
if (!fs.existsSync(promptsDir)) fs.mkdirSync(promptsDir, { recursive: true });
|
|
171
170
|
const promptFileName = `${foundLib.cid}_${key}.md`;
|
|
@@ -210,7 +209,7 @@ function createQuickStart({
|
|
|
210
209
|
}
|
|
211
210
|
|
|
212
211
|
// Save manifest
|
|
213
|
-
|
|
212
|
+
libraryManager.writeManifest(foundLib.cid, foundLib.manifest);
|
|
214
213
|
|
|
215
214
|
return {
|
|
216
215
|
success: true,
|
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
// Central registry of core Sage MCP tools grouped by capability.
|
|
2
|
+
// This is used by suggest_sage_tools to provide lightweight routing
|
|
3
|
+
// and avoids hard-coding tool metadata in multiple places.
|
|
4
|
+
//
|
|
5
|
+
// Weight philosophy:
|
|
6
|
+
// - 1.0: Standard tools (general purpose)
|
|
7
|
+
// - 0.9: Primarily "list/browse" tools (lower-action, exploratory)
|
|
8
|
+
// - 1.1–1.2: High-value "action" tools that accomplish concrete tasks
|
|
9
|
+
|
|
10
|
+
const TOOL_REGISTRY = {
|
|
11
|
+
// ───────────── Prompt workspace tools ─────────────
|
|
12
|
+
search_prompts: {
|
|
13
|
+
category: 'prompt_workspace',
|
|
14
|
+
keywords: ['search', 'find', 'prompt', 'query', 'look', 'locate', 'discover'],
|
|
15
|
+
negativeKeywords: ['create', 'new', 'publish', 'delete'],
|
|
16
|
+
description: 'Search prompts across local workspace and on-chain libraries.',
|
|
17
|
+
whenToUse: 'Use when you need to find existing prompts by keyword, tag, or content.',
|
|
18
|
+
requiredParams: ['query'],
|
|
19
|
+
optionalParams: ['source', 'subdao', 'tags', 'includeContent'],
|
|
20
|
+
weight: 1.0,
|
|
21
|
+
},
|
|
22
|
+
list_prompts: {
|
|
23
|
+
category: 'prompt_workspace',
|
|
24
|
+
keywords: ['list', 'browse', 'prompt', 'workspace'],
|
|
25
|
+
negativeKeywords: ['search', 'publish'],
|
|
26
|
+
description: 'List prompts from local workspace and/or on-chain libraries.',
|
|
27
|
+
whenToUse: 'Use when you want a browseable list of prompts without a specific search query.',
|
|
28
|
+
requiredParams: [],
|
|
29
|
+
optionalParams: ['source', 'library', 'limit'],
|
|
30
|
+
weight: 0.9,
|
|
31
|
+
},
|
|
32
|
+
get_prompt: {
|
|
33
|
+
category: 'prompt_workspace',
|
|
34
|
+
keywords: ['get', 'inspect', 'view', 'prompt', 'details'],
|
|
35
|
+
negativeKeywords: ['search', 'list'],
|
|
36
|
+
description: 'Retrieve a specific prompt by key, including its content.',
|
|
37
|
+
whenToUse: 'Use when you already know the prompt key and want full details for editing or reuse.',
|
|
38
|
+
requiredParams: ['key'],
|
|
39
|
+
optionalParams: ['library'],
|
|
40
|
+
weight: 1.0,
|
|
41
|
+
},
|
|
42
|
+
quick_create_prompt: {
|
|
43
|
+
category: 'prompt_workspace',
|
|
44
|
+
keywords: ['create', 'new', 'write', 'add', 'draft', 'prompt'],
|
|
45
|
+
negativeKeywords: ['find', 'search', 'list'],
|
|
46
|
+
description: 'Create a new prompt with automatic library handling.',
|
|
47
|
+
whenToUse: 'Use when starting fresh with a new prompt idea.',
|
|
48
|
+
requiredParams: ['name', 'content'],
|
|
49
|
+
optionalParams: ['library', 'description', 'tags'],
|
|
50
|
+
weight: 1.2,
|
|
51
|
+
},
|
|
52
|
+
quick_iterate_prompt: {
|
|
53
|
+
category: 'prompt_workspace',
|
|
54
|
+
keywords: ['edit', 'update', 'improve', 'iterate', 'refine'],
|
|
55
|
+
negativeKeywords: ['create', 'search'],
|
|
56
|
+
description: 'Modify an existing prompt in-place, keeping history in the workspace.',
|
|
57
|
+
whenToUse: 'Use when you want to refine or adjust an existing prompt.',
|
|
58
|
+
requiredParams: ['key', 'content'],
|
|
59
|
+
optionalParams: ['library', 'description'],
|
|
60
|
+
weight: 1.1,
|
|
61
|
+
},
|
|
62
|
+
test_prompt: {
|
|
63
|
+
category: 'prompt_workspace',
|
|
64
|
+
keywords: ['test', 'render', 'evaluate', 'prompt', 'variables'],
|
|
65
|
+
negativeKeywords: ['search', 'list'],
|
|
66
|
+
description: 'Test a prompt by filling in ${variable} placeholders and viewing the rendered result.',
|
|
67
|
+
whenToUse: 'Use when you want to verify prompt behavior and variable substitution.',
|
|
68
|
+
requiredParams: ['key'],
|
|
69
|
+
optionalParams: ['library', 'variables'],
|
|
70
|
+
weight: 1.0,
|
|
71
|
+
},
|
|
72
|
+
quick_test_prompt: {
|
|
73
|
+
category: 'prompt_workspace',
|
|
74
|
+
keywords: ['test', 'quick', 'run', 'prompt', 'variables'],
|
|
75
|
+
negativeKeywords: ['search', 'list'],
|
|
76
|
+
description: 'Alias for test_prompt. Quickly test a prompt with variables.',
|
|
77
|
+
whenToUse: 'Use when you want a shortcut to test_prompt for fast validation.',
|
|
78
|
+
requiredParams: ['key'],
|
|
79
|
+
optionalParams: ['variables'],
|
|
80
|
+
weight: 1.0,
|
|
81
|
+
},
|
|
82
|
+
list_workspace_skills: {
|
|
83
|
+
category: 'prompt_workspace',
|
|
84
|
+
keywords: ['skill', 'persona', 'workspace', 'list', 'browse'],
|
|
85
|
+
negativeKeywords: ['governance', 'publish'],
|
|
86
|
+
description: 'List skills/personas defined in the current project workspace.',
|
|
87
|
+
whenToUse: 'Use when you want to see available personas/skills for this project.',
|
|
88
|
+
requiredParams: [],
|
|
89
|
+
optionalParams: ['promptsDir'],
|
|
90
|
+
weight: 1.0,
|
|
91
|
+
},
|
|
92
|
+
improve_prompt: {
|
|
93
|
+
category: 'prompt_workspace',
|
|
94
|
+
keywords: ['improve', 'refine', 'quality', 'analyze', 'prompt'],
|
|
95
|
+
negativeKeywords: ['create', 'publish'],
|
|
96
|
+
description: 'Analyze an existing prompt and suggest improvement areas and interview questions.',
|
|
97
|
+
whenToUse: 'Use when you have a working prompt and want structured suggestions for improvement.',
|
|
98
|
+
requiredParams: ['key'],
|
|
99
|
+
optionalParams: ['library', 'depth', 'focus'],
|
|
100
|
+
weight: 1.0,
|
|
101
|
+
},
|
|
102
|
+
rename_prompt: {
|
|
103
|
+
category: 'prompt_workspace',
|
|
104
|
+
keywords: ['rename', 'key', 'name', 'prompt'],
|
|
105
|
+
negativeKeywords: ['search'],
|
|
106
|
+
description: 'Rename a prompt key and/or display name while preserving content.',
|
|
107
|
+
whenToUse: 'Use when you need to change the identifier or display name of an existing prompt.',
|
|
108
|
+
requiredParams: ['key'],
|
|
109
|
+
optionalParams: ['newKey', 'name'],
|
|
110
|
+
weight: 0.9,
|
|
111
|
+
},
|
|
112
|
+
get_workspace_skill: {
|
|
113
|
+
category: 'prompt_workspace',
|
|
114
|
+
keywords: ['skill', 'persona', 'workspace', 'get', 'inspect'],
|
|
115
|
+
negativeKeywords: ['search'],
|
|
116
|
+
description: 'Load a specific workspace skill by path or key.',
|
|
117
|
+
whenToUse: 'Use when you know which skill you want to inspect or pass into an agent.',
|
|
118
|
+
requiredParams: ['path'],
|
|
119
|
+
optionalParams: [],
|
|
120
|
+
weight: 1.0,
|
|
121
|
+
},
|
|
122
|
+
|
|
123
|
+
// ───────────── Persona / metaprompt tools ─────────────
|
|
124
|
+
list_persona_templates: {
|
|
125
|
+
category: 'persona',
|
|
126
|
+
keywords: ['persona', 'template', 'list', 'browse', 'metaprompt'],
|
|
127
|
+
negativeKeywords: [],
|
|
128
|
+
description: 'List available persona templates (coding assistant, governance helper, etc.).',
|
|
129
|
+
whenToUse: 'Use when you are deciding what kind of assistant/persona to design.',
|
|
130
|
+
requiredParams: [],
|
|
131
|
+
optionalParams: [],
|
|
132
|
+
weight: 1.0,
|
|
133
|
+
},
|
|
134
|
+
run_persona_interview: {
|
|
135
|
+
category: 'persona',
|
|
136
|
+
keywords: ['persona', 'interview', 'one-shot', 'create', 'system prompt'],
|
|
137
|
+
negativeKeywords: ['stepwise', 'stateful'],
|
|
138
|
+
description: 'Build a persona/system prompt in one shot from provided answers.',
|
|
139
|
+
whenToUse: 'Use when you already have answers for the persona slots and just need a system prompt.',
|
|
140
|
+
requiredParams: ['template', 'answers'],
|
|
141
|
+
optionalParams: ['save', 'saveKey'],
|
|
142
|
+
weight: 1.2,
|
|
143
|
+
},
|
|
144
|
+
persona_interview_step: {
|
|
145
|
+
category: 'persona',
|
|
146
|
+
keywords: ['persona', 'interview', 'step', 'slot', 'stateful'],
|
|
147
|
+
negativeKeywords: ['one-shot'],
|
|
148
|
+
description: 'Advance a stateful persona interview by one step, returning slot metadata.',
|
|
149
|
+
whenToUse: 'Use when you want the host LLM to run a multi-turn interview over persona slots.',
|
|
150
|
+
requiredParams: [],
|
|
151
|
+
optionalParams: ['template', 'stateToken', 'answer'],
|
|
152
|
+
weight: 1.1,
|
|
153
|
+
},
|
|
154
|
+
save_metaprompt: {
|
|
155
|
+
category: 'persona',
|
|
156
|
+
keywords: ['metaprompt', 'save', 'store', 'persona'],
|
|
157
|
+
negativeKeywords: [],
|
|
158
|
+
description: 'Save a metaprompt/persona definition into the Sage workspace.',
|
|
159
|
+
whenToUse: 'Use when you want to persist a finalized persona or system prompt.',
|
|
160
|
+
requiredParams: ['title', 'body'],
|
|
161
|
+
optionalParams: ['summary', 'tags', 'appendAgentsFile'],
|
|
162
|
+
weight: 1.0,
|
|
163
|
+
},
|
|
164
|
+
get_metaprompt: {
|
|
165
|
+
category: 'persona',
|
|
166
|
+
keywords: ['metaprompt', 'persona', 'load', 'get'],
|
|
167
|
+
negativeKeywords: [],
|
|
168
|
+
description: 'Load an existing metaprompt/persona by slug.',
|
|
169
|
+
whenToUse: 'Use when you want to reuse or inspect a previously saved persona.',
|
|
170
|
+
requiredParams: ['slug'],
|
|
171
|
+
optionalParams: [],
|
|
172
|
+
weight: 1.0,
|
|
173
|
+
},
|
|
174
|
+
|
|
175
|
+
// ───────────── Library / manifest tools ─────────────
|
|
176
|
+
list_libraries: {
|
|
177
|
+
category: 'libraries',
|
|
178
|
+
keywords: ['library', 'libraries', 'list', 'browse', 'manifest'],
|
|
179
|
+
negativeKeywords: [],
|
|
180
|
+
description: 'List available prompt libraries from local workspace or on-chain.',
|
|
181
|
+
whenToUse: 'Use when you want to see which libraries/manifests are available.',
|
|
182
|
+
requiredParams: [],
|
|
183
|
+
optionalParams: ['source', 'subdao', 'limit'],
|
|
184
|
+
weight: 1.0,
|
|
185
|
+
},
|
|
186
|
+
get_prompts_from_manifest: {
|
|
187
|
+
category: 'libraries',
|
|
188
|
+
keywords: ['manifest', 'library', 'prompt', 'list', 'get'],
|
|
189
|
+
negativeKeywords: [],
|
|
190
|
+
description: 'Get all prompts from a specific manifest by CID.',
|
|
191
|
+
whenToUse: 'Use when you have a manifest CID and want to inspect its prompts.',
|
|
192
|
+
requiredParams: ['manifestCid'],
|
|
193
|
+
optionalParams: ['includeContent'],
|
|
194
|
+
weight: 1.0,
|
|
195
|
+
},
|
|
196
|
+
list_templates: {
|
|
197
|
+
category: 'libraries',
|
|
198
|
+
keywords: ['template', 'list', 'browse', 'prompt'],
|
|
199
|
+
negativeKeywords: [],
|
|
200
|
+
description: 'List available prompt templates for quick creation.',
|
|
201
|
+
whenToUse: 'Use when you want to see reusable prompt templates (not personas).',
|
|
202
|
+
requiredParams: [],
|
|
203
|
+
optionalParams: ['category', 'search'],
|
|
204
|
+
weight: 0.9,
|
|
205
|
+
},
|
|
206
|
+
create_from_template: {
|
|
207
|
+
category: 'libraries',
|
|
208
|
+
keywords: ['template', 'create', 'new', 'prompt'],
|
|
209
|
+
negativeKeywords: [],
|
|
210
|
+
description: 'Create a new prompt from a template and save into a library.',
|
|
211
|
+
whenToUse: 'Use when you want to quickly scaffold a prompt from an existing template.',
|
|
212
|
+
requiredParams: ['template', 'customize'],
|
|
213
|
+
optionalParams: ['library', 'name'],
|
|
214
|
+
weight: 1.1,
|
|
215
|
+
},
|
|
216
|
+
get_prompt_content: {
|
|
217
|
+
category: 'libraries',
|
|
218
|
+
keywords: ['get', 'prompt', 'content', 'ipfs', 'cid'],
|
|
219
|
+
negativeKeywords: ['search'],
|
|
220
|
+
description: 'Fetch full prompt content from IPFS by CID.',
|
|
221
|
+
whenToUse: 'Use when you have an IPFS CID and need the underlying prompt content.',
|
|
222
|
+
requiredParams: ['cid'],
|
|
223
|
+
optionalParams: [],
|
|
224
|
+
weight: 1.0,
|
|
225
|
+
},
|
|
226
|
+
|
|
227
|
+
// ───────────── Governance tools ─────────────
|
|
228
|
+
publish_manifest_flow: {
|
|
229
|
+
category: 'governance',
|
|
230
|
+
keywords: ['publish', 'manifest', 'dao', 'subdao', 'governance'],
|
|
231
|
+
negativeKeywords: [],
|
|
232
|
+
description: 'Prepare a manifest for on-chain publishing and generate CLI commands.',
|
|
233
|
+
whenToUse: 'Use when you are ready to publish a library/manifest to a SubDAO.',
|
|
234
|
+
requiredParams: ['manifest'],
|
|
235
|
+
optionalParams: ['subdao', 'description', 'dry_run'],
|
|
236
|
+
weight: 1.2,
|
|
237
|
+
},
|
|
238
|
+
list_proposals: {
|
|
239
|
+
category: 'governance',
|
|
240
|
+
keywords: ['proposal', 'governance', 'list', 'dao', 'subdao'],
|
|
241
|
+
negativeKeywords: [],
|
|
242
|
+
description: 'List active proposals for a specific SubDAO.',
|
|
243
|
+
whenToUse: 'Use when you want to inspect or track current governance proposals.',
|
|
244
|
+
requiredParams: [],
|
|
245
|
+
optionalParams: ['state', 'subdao', 'limit'],
|
|
246
|
+
weight: 1.0,
|
|
247
|
+
},
|
|
248
|
+
suggest_subdaos_for_library: {
|
|
249
|
+
category: 'governance',
|
|
250
|
+
keywords: ['subdao', 'suggest', 'library', 'publish', 'dao'],
|
|
251
|
+
negativeKeywords: [],
|
|
252
|
+
description: 'Suggest suitable SubDAOs for publishing a given library manifest.',
|
|
253
|
+
whenToUse: 'Use when you have a library and want advice on where to publish it.',
|
|
254
|
+
requiredParams: ['library'],
|
|
255
|
+
optionalParams: ['limit'],
|
|
256
|
+
weight: 1.0,
|
|
257
|
+
},
|
|
258
|
+
generate_publishing_commands: {
|
|
259
|
+
category: 'governance',
|
|
260
|
+
keywords: ['publish', 'commands', 'cli', 'dao', 'subdao'],
|
|
261
|
+
negativeKeywords: [],
|
|
262
|
+
description: 'Generate CLI commands for validating, uploading, and proposing a manifest.',
|
|
263
|
+
whenToUse: 'Use after selecting a SubDAO to get concrete CLI commands for publishing.',
|
|
264
|
+
requiredParams: ['library'],
|
|
265
|
+
optionalParams: ['target'],
|
|
266
|
+
weight: 1.0,
|
|
267
|
+
},
|
|
268
|
+
|
|
269
|
+
// ───────────── Treasury / SubDAO tools ─────────────
|
|
270
|
+
list_subdaos: {
|
|
271
|
+
category: 'treasury',
|
|
272
|
+
keywords: ['subdao', 'dao', 'list', 'treasury', 'governance'],
|
|
273
|
+
negativeKeywords: [],
|
|
274
|
+
description: 'List all available SubDAOs in the Sage Protocol.',
|
|
275
|
+
whenToUse: 'Use when you want an overview of existing SubDAOs/treasuries.',
|
|
276
|
+
requiredParams: [],
|
|
277
|
+
optionalParams: ['limit'],
|
|
278
|
+
weight: 0.9,
|
|
279
|
+
},
|
|
280
|
+
list_subdao_libraries: {
|
|
281
|
+
category: 'treasury',
|
|
282
|
+
keywords: ['subdao', 'library', 'libraries', 'list'],
|
|
283
|
+
negativeKeywords: [],
|
|
284
|
+
description: 'List libraries associated with a specific SubDAO.',
|
|
285
|
+
whenToUse: 'Use when you want to see what libraries a SubDAO currently governs.',
|
|
286
|
+
requiredParams: ['subdao'],
|
|
287
|
+
optionalParams: [],
|
|
288
|
+
weight: 1.0,
|
|
289
|
+
},
|
|
290
|
+
|
|
291
|
+
// ───────────── Discovery / helper tools ─────────────
|
|
292
|
+
trending_prompts: {
|
|
293
|
+
category: 'discovery',
|
|
294
|
+
keywords: ['trending', 'popular', 'recent', 'discover', 'prompt'],
|
|
295
|
+
negativeKeywords: ['create'],
|
|
296
|
+
description: 'List trending prompts from recent LibraryRegistry updates.',
|
|
297
|
+
whenToUse: 'Use when you want to discover popular or recently active prompts.',
|
|
298
|
+
requiredParams: [],
|
|
299
|
+
optionalParams: ['decayMinutes', 'limit'],
|
|
300
|
+
weight: 0.9,
|
|
301
|
+
},
|
|
302
|
+
help: {
|
|
303
|
+
category: 'discovery',
|
|
304
|
+
keywords: ['help', 'usage', 'docs', 'explain'],
|
|
305
|
+
negativeKeywords: [],
|
|
306
|
+
description: 'Get help on how to use Sage MCP tools and workflows.',
|
|
307
|
+
whenToUse: 'Use when you need guidance on which Sage tools to use or how to call them.',
|
|
308
|
+
requiredParams: [],
|
|
309
|
+
optionalParams: ['topic'],
|
|
310
|
+
weight: 0.9,
|
|
311
|
+
},
|
|
312
|
+
};
|
|
313
|
+
|
|
314
|
+
function getToolsForCategory(category) {
|
|
315
|
+
return Object.entries(TOOL_REGISTRY)
|
|
316
|
+
.filter(([, meta]) => meta.category === category)
|
|
317
|
+
.map(([name, meta]) => ({ name, ...meta }));
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
function getToolMeta(name) {
|
|
321
|
+
const meta = TOOL_REGISTRY[name];
|
|
322
|
+
if (!meta) return null;
|
|
323
|
+
return { name, ...meta };
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
module.exports = {
|
|
327
|
+
TOOL_REGISTRY,
|
|
328
|
+
getToolsForCategory,
|
|
329
|
+
getToolMeta,
|
|
330
|
+
};
|
|
@@ -5,6 +5,24 @@ function createToolArgsValidator({ zodModule } = {}) {
|
|
|
5
5
|
}
|
|
6
6
|
|
|
7
7
|
const schemas = {
|
|
8
|
+
suggest_sage_tools: Z.object({
|
|
9
|
+
goal: Z.string().min(1).max(1000),
|
|
10
|
+
stage: Z.enum([
|
|
11
|
+
'prompt_workspace',
|
|
12
|
+
'persona',
|
|
13
|
+
'libraries',
|
|
14
|
+
'governance',
|
|
15
|
+
'treasury',
|
|
16
|
+
'discovery',
|
|
17
|
+
]).optional(),
|
|
18
|
+
context: Z.object({
|
|
19
|
+
hasWorkspace: Z.boolean().optional(),
|
|
20
|
+
hasWallet: Z.boolean().optional(),
|
|
21
|
+
currentTask: Z.string().max(200).optional(),
|
|
22
|
+
}).optional(),
|
|
23
|
+
limit: Z.number().int().min(1).max(10).optional().default(5),
|
|
24
|
+
includeAlternatives: Z.boolean().optional().default(false),
|
|
25
|
+
}),
|
|
8
26
|
search_prompts: Z.object({
|
|
9
27
|
query: Z.string().max(256).optional().default(''),
|
|
10
28
|
source: Z.enum(['local', 'onchain', 'all']).optional().default('all'),
|
|
@@ -38,6 +56,19 @@ function createToolArgsValidator({ zodModule } = {}) {
|
|
|
38
56
|
model: Z.string().max(100).optional(),
|
|
39
57
|
interviewStyle: Z.string().max(200).optional(),
|
|
40
58
|
}),
|
|
59
|
+
list_persona_templates: Z.object({}),
|
|
60
|
+
run_persona_interview: Z.object({
|
|
61
|
+
template: Z.string().min(1).max(200),
|
|
62
|
+
answers: Z.record(Z.any()),
|
|
63
|
+
save: Z.boolean().optional().default(false),
|
|
64
|
+
saveKey: Z.string().min(1).max(200).optional(),
|
|
65
|
+
}),
|
|
66
|
+
persona_interview_step: Z.object({
|
|
67
|
+
// template is required on first call, optional when stateToken is provided
|
|
68
|
+
template: Z.string().min(1).max(200).optional().default('custom'),
|
|
69
|
+
stateToken: Z.string().max(16000).optional(), // increased for slots + answers
|
|
70
|
+
answer: Z.string().max(8000).optional(),
|
|
71
|
+
}),
|
|
41
72
|
save_metaprompt: Z.object({
|
|
42
73
|
title: Z.string().min(1).max(200),
|
|
43
74
|
summary: Z.string().max(500).optional().default(''),
|