clawdentials-mcp 0.1.0 → 0.7.2
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/README.md +310 -58
- package/dist/index.d.ts +1 -1
- package/dist/index.js +225 -18
- package/dist/schemas/index.d.ts +141 -0
- package/dist/schemas/index.js +54 -0
- package/dist/services/firestore.d.ts +45 -2
- package/dist/services/firestore.js +410 -6
- package/dist/services/payments/alby.d.ts +104 -0
- package/dist/services/payments/alby.js +239 -0
- package/dist/services/payments/breez.d.ts +91 -0
- package/dist/services/payments/breez.js +267 -0
- package/dist/services/payments/cashu.d.ts +127 -0
- package/dist/services/payments/cashu.js +248 -0
- package/dist/services/payments/coinremitter.d.ts +84 -0
- package/dist/services/payments/coinremitter.js +176 -0
- package/dist/services/payments/index.d.ts +132 -0
- package/dist/services/payments/index.js +180 -0
- package/dist/services/payments/oxapay.d.ts +89 -0
- package/dist/services/payments/oxapay.js +221 -0
- package/dist/services/payments/x402.d.ts +61 -0
- package/dist/services/payments/x402.js +94 -0
- package/dist/services/payments/zbd.d.ts +88 -0
- package/dist/services/payments/zbd.js +221 -0
- package/dist/tools/admin.d.ts +195 -0
- package/dist/tools/admin.js +210 -0
- package/dist/tools/agent.d.ts +197 -0
- package/dist/tools/agent.js +200 -0
- package/dist/tools/escrow.d.ts +74 -16
- package/dist/tools/escrow.js +139 -28
- package/dist/tools/index.d.ts +3 -0
- package/dist/tools/index.js +3 -0
- package/dist/tools/payment.d.ts +144 -0
- package/dist/tools/payment.js +376 -0
- package/dist/types/index.d.ts +44 -1
- package/package.json +18 -2
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import { adminCreditBalanceSchema, adminProcessWithdrawalSchema, adminListWithdrawalsSchema, } from '../schemas/index.js';
|
|
2
|
+
import { ADMIN_SECRET, creditBalance, getBalance, getAgent, processWithdrawal, listWithdrawals, refundEscrow, getEscrow, collections, } from '../services/firestore.js';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
// Admin refund schema
|
|
5
|
+
const adminRefundSchema = z.object({
|
|
6
|
+
adminSecret: z.string().min(1).describe('Admin secret key'),
|
|
7
|
+
escrowId: z.string().min(1).describe('ID of the disputed escrow to refund'),
|
|
8
|
+
});
|
|
9
|
+
export const adminTools = {
|
|
10
|
+
admin_credit_balance: {
|
|
11
|
+
description: 'Credit funds to an agent\'s balance after receiving manual payment (PayPal/Venmo).',
|
|
12
|
+
inputSchema: adminCreditBalanceSchema,
|
|
13
|
+
handler: async (input) => {
|
|
14
|
+
// Validate admin secret
|
|
15
|
+
if (input.adminSecret !== ADMIN_SECRET) {
|
|
16
|
+
return {
|
|
17
|
+
success: false,
|
|
18
|
+
error: 'Invalid admin secret',
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
// Check agent exists
|
|
22
|
+
const agent = await getAgent(input.agentId);
|
|
23
|
+
if (!agent) {
|
|
24
|
+
return {
|
|
25
|
+
success: false,
|
|
26
|
+
error: `Agent not found: ${input.agentId}`,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
const oldBalance = await getBalance(input.agentId);
|
|
30
|
+
const newBalance = await creditBalance(input.agentId, input.amount, input.notes);
|
|
31
|
+
return {
|
|
32
|
+
success: true,
|
|
33
|
+
message: `Credited ${input.amount} ${input.currency} to ${input.agentId}`,
|
|
34
|
+
agentId: input.agentId,
|
|
35
|
+
oldBalance,
|
|
36
|
+
credited: input.amount,
|
|
37
|
+
newBalance,
|
|
38
|
+
currency: input.currency,
|
|
39
|
+
notes: input.notes,
|
|
40
|
+
};
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
admin_list_withdrawals: {
|
|
44
|
+
description: 'List pending withdrawal requests.',
|
|
45
|
+
inputSchema: adminListWithdrawalsSchema,
|
|
46
|
+
handler: async (input) => {
|
|
47
|
+
// Validate admin secret
|
|
48
|
+
if (input.adminSecret !== ADMIN_SECRET) {
|
|
49
|
+
return {
|
|
50
|
+
success: false,
|
|
51
|
+
error: 'Invalid admin secret',
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
const withdrawals = await listWithdrawals(input.status, input.limit);
|
|
55
|
+
return {
|
|
56
|
+
success: true,
|
|
57
|
+
withdrawals: withdrawals.map(w => ({
|
|
58
|
+
id: w.id,
|
|
59
|
+
agentId: w.agentId,
|
|
60
|
+
amount: w.amount,
|
|
61
|
+
currency: w.currency,
|
|
62
|
+
status: w.status,
|
|
63
|
+
paymentMethod: w.paymentMethod,
|
|
64
|
+
requestedAt: w.requestedAt.toISOString(),
|
|
65
|
+
processedAt: w.processedAt?.toISOString() ?? null,
|
|
66
|
+
notes: w.notes,
|
|
67
|
+
})),
|
|
68
|
+
count: withdrawals.length,
|
|
69
|
+
};
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
admin_process_withdrawal: {
|
|
73
|
+
description: 'Process a withdrawal request - mark as completed (after sending payment) or rejected.',
|
|
74
|
+
inputSchema: adminProcessWithdrawalSchema,
|
|
75
|
+
handler: async (input) => {
|
|
76
|
+
// Validate admin secret
|
|
77
|
+
if (input.adminSecret !== ADMIN_SECRET) {
|
|
78
|
+
return {
|
|
79
|
+
success: false,
|
|
80
|
+
error: 'Invalid admin secret',
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
try {
|
|
84
|
+
const withdrawal = await processWithdrawal(input.withdrawalId, input.action, input.notes);
|
|
85
|
+
if (!withdrawal) {
|
|
86
|
+
return {
|
|
87
|
+
success: false,
|
|
88
|
+
error: `Withdrawal not found: ${input.withdrawalId}`,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
const actionText = input.action === 'complete' ? 'completed' : 'rejected';
|
|
92
|
+
return {
|
|
93
|
+
success: true,
|
|
94
|
+
message: `Withdrawal ${actionText}`,
|
|
95
|
+
withdrawal: {
|
|
96
|
+
id: withdrawal.id,
|
|
97
|
+
agentId: withdrawal.agentId,
|
|
98
|
+
amount: withdrawal.amount,
|
|
99
|
+
currency: withdrawal.currency,
|
|
100
|
+
status: withdrawal.status,
|
|
101
|
+
paymentMethod: withdrawal.paymentMethod,
|
|
102
|
+
processedAt: withdrawal.processedAt?.toISOString(),
|
|
103
|
+
notes: withdrawal.notes,
|
|
104
|
+
},
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
return {
|
|
109
|
+
success: false,
|
|
110
|
+
error: error instanceof Error ? error.message : 'Failed to process withdrawal',
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
admin_refund_escrow: {
|
|
116
|
+
description: 'Refund a disputed escrow back to the client.',
|
|
117
|
+
inputSchema: adminRefundSchema,
|
|
118
|
+
handler: async (input) => {
|
|
119
|
+
// Validate admin secret
|
|
120
|
+
if (input.adminSecret !== ADMIN_SECRET) {
|
|
121
|
+
return {
|
|
122
|
+
success: false,
|
|
123
|
+
error: 'Invalid admin secret',
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
const existingEscrow = await getEscrow(input.escrowId);
|
|
127
|
+
if (!existingEscrow) {
|
|
128
|
+
return {
|
|
129
|
+
success: false,
|
|
130
|
+
error: `Escrow not found: ${input.escrowId}`,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
if (existingEscrow.status !== 'disputed') {
|
|
134
|
+
return {
|
|
135
|
+
success: false,
|
|
136
|
+
error: `Can only refund disputed escrows. Current status: ${existingEscrow.status}`,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
try {
|
|
140
|
+
const escrow = await refundEscrow(input.escrowId);
|
|
141
|
+
const newBalance = await getBalance(existingEscrow.clientAgentId);
|
|
142
|
+
return {
|
|
143
|
+
success: true,
|
|
144
|
+
message: `Refunded ${existingEscrow.amount} ${existingEscrow.currency} to ${existingEscrow.clientAgentId}`,
|
|
145
|
+
escrow: {
|
|
146
|
+
id: escrow.id,
|
|
147
|
+
status: escrow.status,
|
|
148
|
+
amount: existingEscrow.amount,
|
|
149
|
+
currency: existingEscrow.currency,
|
|
150
|
+
},
|
|
151
|
+
clientNewBalance: newBalance,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
catch (error) {
|
|
155
|
+
return {
|
|
156
|
+
success: false,
|
|
157
|
+
error: error instanceof Error ? error.message : 'Failed to refund escrow',
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
},
|
|
161
|
+
},
|
|
162
|
+
admin_nostr_json: {
|
|
163
|
+
description: 'Generate the NIP-05 nostr.json file content for all registered agents. Host this at clawdentials.com/.well-known/nostr.json',
|
|
164
|
+
inputSchema: z.object({
|
|
165
|
+
adminSecret: z.string().min(1).describe('Admin secret key'),
|
|
166
|
+
}),
|
|
167
|
+
handler: async (input) => {
|
|
168
|
+
// Validate admin secret
|
|
169
|
+
if (input.adminSecret !== ADMIN_SECRET) {
|
|
170
|
+
return {
|
|
171
|
+
success: false,
|
|
172
|
+
error: 'Invalid admin secret',
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
try {
|
|
176
|
+
// Get all agents with Nostr pubkeys
|
|
177
|
+
const snapshot = await collections.agents().get();
|
|
178
|
+
const names = {};
|
|
179
|
+
for (const doc of snapshot.docs) {
|
|
180
|
+
const data = doc.data();
|
|
181
|
+
if (data.nostrPubkey) {
|
|
182
|
+
// Use the agent name (lowercase, sanitized) as the identifier
|
|
183
|
+
const identifier = doc.id.toLowerCase().replace(/[^a-z0-9-_.]/g, '');
|
|
184
|
+
names[identifier] = data.nostrPubkey;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
// Generate the nostr.json content
|
|
188
|
+
const nostrJson = {
|
|
189
|
+
names,
|
|
190
|
+
// Optional: add relay hints
|
|
191
|
+
// relays: {}
|
|
192
|
+
};
|
|
193
|
+
return {
|
|
194
|
+
success: true,
|
|
195
|
+
message: 'Host this JSON at: https://clawdentials.com/.well-known/nostr.json',
|
|
196
|
+
agentCount: Object.keys(names).length,
|
|
197
|
+
nostrJson,
|
|
198
|
+
// Also return as string for easy copy-paste
|
|
199
|
+
nostrJsonString: JSON.stringify(nostrJson, null, 2),
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
catch (error) {
|
|
203
|
+
return {
|
|
204
|
+
success: false,
|
|
205
|
+
error: error instanceof Error ? error.message : 'Failed to generate nostr.json',
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
},
|
|
209
|
+
},
|
|
210
|
+
};
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import { type AgentRegisterInput, type AgentScoreInput, type AgentSearchInput, type AgentBalanceInput, type WithdrawRequestInput } from '../schemas/index.js';
|
|
2
|
+
export declare const agentTools: {
|
|
3
|
+
agent_register: {
|
|
4
|
+
description: string;
|
|
5
|
+
inputSchema: import("zod").ZodObject<{
|
|
6
|
+
name: import("zod").ZodString;
|
|
7
|
+
description: import("zod").ZodString;
|
|
8
|
+
skills: import("zod").ZodArray<import("zod").ZodString, "many">;
|
|
9
|
+
}, "strip", import("zod").ZodTypeAny, {
|
|
10
|
+
name: string;
|
|
11
|
+
description: string;
|
|
12
|
+
skills: string[];
|
|
13
|
+
}, {
|
|
14
|
+
name: string;
|
|
15
|
+
description: string;
|
|
16
|
+
skills: string[];
|
|
17
|
+
}>;
|
|
18
|
+
handler: (input: AgentRegisterInput) => Promise<{
|
|
19
|
+
success: boolean;
|
|
20
|
+
message: string;
|
|
21
|
+
credentials: {
|
|
22
|
+
apiKey: string;
|
|
23
|
+
nostr: {
|
|
24
|
+
nsec: string;
|
|
25
|
+
npub: string;
|
|
26
|
+
nip05: string;
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
agent: {
|
|
30
|
+
id: string;
|
|
31
|
+
name: string;
|
|
32
|
+
description: string;
|
|
33
|
+
skills: string[];
|
|
34
|
+
verified: boolean;
|
|
35
|
+
subscriptionTier: import("../types/index.js").SubscriptionTier;
|
|
36
|
+
balance: number;
|
|
37
|
+
nip05: string | undefined;
|
|
38
|
+
createdAt: string;
|
|
39
|
+
stats: import("../types/index.js").AgentStats;
|
|
40
|
+
reputationScore: number;
|
|
41
|
+
};
|
|
42
|
+
error?: undefined;
|
|
43
|
+
} | {
|
|
44
|
+
success: boolean;
|
|
45
|
+
error: string;
|
|
46
|
+
message?: undefined;
|
|
47
|
+
credentials?: undefined;
|
|
48
|
+
agent?: undefined;
|
|
49
|
+
}>;
|
|
50
|
+
};
|
|
51
|
+
agent_score: {
|
|
52
|
+
description: string;
|
|
53
|
+
inputSchema: import("zod").ZodObject<{
|
|
54
|
+
agentId: import("zod").ZodString;
|
|
55
|
+
}, "strip", import("zod").ZodTypeAny, {
|
|
56
|
+
agentId: string;
|
|
57
|
+
}, {
|
|
58
|
+
agentId: string;
|
|
59
|
+
}>;
|
|
60
|
+
handler: (input: AgentScoreInput) => Promise<{
|
|
61
|
+
success: boolean;
|
|
62
|
+
error: string;
|
|
63
|
+
agent?: undefined;
|
|
64
|
+
} | {
|
|
65
|
+
success: boolean;
|
|
66
|
+
agent: {
|
|
67
|
+
id: string;
|
|
68
|
+
name: string;
|
|
69
|
+
reputationScore: number;
|
|
70
|
+
badges: string[];
|
|
71
|
+
verified: boolean;
|
|
72
|
+
subscriptionTier: import("../types/index.js").SubscriptionTier;
|
|
73
|
+
stats: {
|
|
74
|
+
tasksCompleted: number;
|
|
75
|
+
totalEarned: number;
|
|
76
|
+
successRate: number;
|
|
77
|
+
disputeCount: number;
|
|
78
|
+
disputeRate: number;
|
|
79
|
+
avgCompletionTime: number;
|
|
80
|
+
};
|
|
81
|
+
accountAgeDays: number;
|
|
82
|
+
};
|
|
83
|
+
error?: undefined;
|
|
84
|
+
}>;
|
|
85
|
+
};
|
|
86
|
+
agent_search: {
|
|
87
|
+
description: string;
|
|
88
|
+
inputSchema: import("zod").ZodObject<{
|
|
89
|
+
skill: import("zod").ZodOptional<import("zod").ZodString>;
|
|
90
|
+
verified: import("zod").ZodOptional<import("zod").ZodBoolean>;
|
|
91
|
+
minTasksCompleted: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
92
|
+
limit: import("zod").ZodDefault<import("zod").ZodNumber>;
|
|
93
|
+
}, "strip", import("zod").ZodTypeAny, {
|
|
94
|
+
limit: number;
|
|
95
|
+
skill?: string | undefined;
|
|
96
|
+
verified?: boolean | undefined;
|
|
97
|
+
minTasksCompleted?: number | undefined;
|
|
98
|
+
}, {
|
|
99
|
+
skill?: string | undefined;
|
|
100
|
+
verified?: boolean | undefined;
|
|
101
|
+
minTasksCompleted?: number | undefined;
|
|
102
|
+
limit?: number | undefined;
|
|
103
|
+
}>;
|
|
104
|
+
handler: (input: AgentSearchInput) => Promise<{
|
|
105
|
+
success: boolean;
|
|
106
|
+
message: string;
|
|
107
|
+
agents: never[];
|
|
108
|
+
count: number;
|
|
109
|
+
} | {
|
|
110
|
+
success: boolean;
|
|
111
|
+
agents: {
|
|
112
|
+
id: string;
|
|
113
|
+
name: string;
|
|
114
|
+
description: string;
|
|
115
|
+
skills: string[];
|
|
116
|
+
verified: boolean;
|
|
117
|
+
subscriptionTier: import("../types/index.js").SubscriptionTier;
|
|
118
|
+
reputationScore: number;
|
|
119
|
+
stats: {
|
|
120
|
+
tasksCompleted: number;
|
|
121
|
+
totalEarned: number;
|
|
122
|
+
disputeRate: number;
|
|
123
|
+
};
|
|
124
|
+
}[];
|
|
125
|
+
count: number;
|
|
126
|
+
message?: undefined;
|
|
127
|
+
}>;
|
|
128
|
+
};
|
|
129
|
+
agent_balance: {
|
|
130
|
+
description: string;
|
|
131
|
+
inputSchema: import("zod").ZodObject<{
|
|
132
|
+
agentId: import("zod").ZodString;
|
|
133
|
+
apiKey: import("zod").ZodString;
|
|
134
|
+
}, "strip", import("zod").ZodTypeAny, {
|
|
135
|
+
apiKey: string;
|
|
136
|
+
agentId: string;
|
|
137
|
+
}, {
|
|
138
|
+
apiKey: string;
|
|
139
|
+
agentId: string;
|
|
140
|
+
}>;
|
|
141
|
+
handler: (input: AgentBalanceInput) => Promise<{
|
|
142
|
+
success: boolean;
|
|
143
|
+
error: string;
|
|
144
|
+
agentId?: undefined;
|
|
145
|
+
balance?: undefined;
|
|
146
|
+
currency?: undefined;
|
|
147
|
+
totalEarned?: undefined;
|
|
148
|
+
} | {
|
|
149
|
+
success: boolean;
|
|
150
|
+
agentId: string;
|
|
151
|
+
balance: number;
|
|
152
|
+
currency: string;
|
|
153
|
+
totalEarned: number;
|
|
154
|
+
error?: undefined;
|
|
155
|
+
}>;
|
|
156
|
+
};
|
|
157
|
+
withdraw_request: {
|
|
158
|
+
description: string;
|
|
159
|
+
inputSchema: import("zod").ZodObject<{
|
|
160
|
+
agentId: import("zod").ZodString;
|
|
161
|
+
apiKey: import("zod").ZodString;
|
|
162
|
+
amount: import("zod").ZodNumber;
|
|
163
|
+
currency: import("zod").ZodDefault<import("zod").ZodEnum<["USD", "USDC", "BTC"]>>;
|
|
164
|
+
paymentMethod: import("zod").ZodString;
|
|
165
|
+
}, "strip", import("zod").ZodTypeAny, {
|
|
166
|
+
amount: number;
|
|
167
|
+
currency: "USD" | "USDC" | "BTC";
|
|
168
|
+
apiKey: string;
|
|
169
|
+
agentId: string;
|
|
170
|
+
paymentMethod: string;
|
|
171
|
+
}, {
|
|
172
|
+
amount: number;
|
|
173
|
+
apiKey: string;
|
|
174
|
+
agentId: string;
|
|
175
|
+
paymentMethod: string;
|
|
176
|
+
currency?: "USD" | "USDC" | "BTC" | undefined;
|
|
177
|
+
}>;
|
|
178
|
+
handler: (input: WithdrawRequestInput) => Promise<{
|
|
179
|
+
success: boolean;
|
|
180
|
+
error: string;
|
|
181
|
+
message?: undefined;
|
|
182
|
+
withdrawal?: undefined;
|
|
183
|
+
} | {
|
|
184
|
+
success: boolean;
|
|
185
|
+
message: string;
|
|
186
|
+
withdrawal: {
|
|
187
|
+
id: string;
|
|
188
|
+
amount: number;
|
|
189
|
+
currency: import("../types/index.js").Currency;
|
|
190
|
+
status: import("../types/index.js").WithdrawalStatus;
|
|
191
|
+
paymentMethod: string;
|
|
192
|
+
requestedAt: string;
|
|
193
|
+
};
|
|
194
|
+
error?: undefined;
|
|
195
|
+
}>;
|
|
196
|
+
};
|
|
197
|
+
};
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import { agentRegisterSchema, agentScoreSchema, agentSearchSchema, agentBalanceSchema, withdrawRequestSchema, } from '../schemas/index.js';
|
|
2
|
+
import { createAgent, getAgent, searchAgents, calculateReputationScore, validateApiKey, getBalance, createWithdrawal, } from '../services/firestore.js';
|
|
3
|
+
export const agentTools = {
|
|
4
|
+
agent_register: {
|
|
5
|
+
description: 'Register as an agent on Clawdentials. Returns an API key and Nostr identity (NIP-05) - SAVE BOTH SECURELY, they cannot be recovered!',
|
|
6
|
+
inputSchema: agentRegisterSchema,
|
|
7
|
+
handler: async (input) => {
|
|
8
|
+
try {
|
|
9
|
+
const { agent, apiKey, nostr } = await createAgent({
|
|
10
|
+
name: input.name,
|
|
11
|
+
description: input.description,
|
|
12
|
+
skills: input.skills,
|
|
13
|
+
verified: false,
|
|
14
|
+
subscriptionTier: 'free',
|
|
15
|
+
});
|
|
16
|
+
return {
|
|
17
|
+
success: true,
|
|
18
|
+
message: `Agent "${input.name}" registered successfully. SAVE YOUR CREDENTIALS - they cannot be recovered!`,
|
|
19
|
+
credentials: {
|
|
20
|
+
apiKey, // Only returned once!
|
|
21
|
+
nostr: {
|
|
22
|
+
nsec: nostr.nsec, // Private key - SAVE THIS!
|
|
23
|
+
npub: nostr.npub, // Public key (shareable)
|
|
24
|
+
nip05: nostr.nip05, // Verified identity: name@clawdentials.com
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
agent: {
|
|
28
|
+
id: agent.id,
|
|
29
|
+
name: agent.name,
|
|
30
|
+
description: agent.description,
|
|
31
|
+
skills: agent.skills,
|
|
32
|
+
verified: agent.verified,
|
|
33
|
+
subscriptionTier: agent.subscriptionTier,
|
|
34
|
+
balance: agent.balance,
|
|
35
|
+
nip05: agent.nip05,
|
|
36
|
+
createdAt: agent.createdAt.toISOString(),
|
|
37
|
+
stats: agent.stats,
|
|
38
|
+
reputationScore: calculateReputationScore(agent),
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
if (error instanceof Error && error.message.includes('already exists')) {
|
|
44
|
+
return {
|
|
45
|
+
success: false,
|
|
46
|
+
error: `Agent with name "${input.name}" already exists. Choose a different name.`,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
return {
|
|
50
|
+
success: false,
|
|
51
|
+
error: error instanceof Error ? error.message : 'Failed to register agent',
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
agent_score: {
|
|
57
|
+
description: 'Get the reputation score and stats for an agent. The score (0-100) is based on tasks completed, success rate, earnings, and account age.',
|
|
58
|
+
inputSchema: agentScoreSchema,
|
|
59
|
+
handler: async (input) => {
|
|
60
|
+
const agent = await getAgent(input.agentId);
|
|
61
|
+
if (!agent) {
|
|
62
|
+
return {
|
|
63
|
+
success: false,
|
|
64
|
+
error: `Agent not found: ${input.agentId}`,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
const reputationScore = calculateReputationScore(agent);
|
|
68
|
+
// Determine badge based on score and stats
|
|
69
|
+
const badges = [];
|
|
70
|
+
if (agent.verified)
|
|
71
|
+
badges.push('Verified');
|
|
72
|
+
if (agent.stats.tasksCompleted >= 100)
|
|
73
|
+
badges.push('Experienced');
|
|
74
|
+
if (agent.stats.tasksCompleted >= 1000)
|
|
75
|
+
badges.push('Expert');
|
|
76
|
+
if (agent.stats.disputeRate < 1 && agent.stats.tasksCompleted >= 10)
|
|
77
|
+
badges.push('Reliable');
|
|
78
|
+
if (reputationScore >= 80)
|
|
79
|
+
badges.push('Top Performer');
|
|
80
|
+
return {
|
|
81
|
+
success: true,
|
|
82
|
+
agent: {
|
|
83
|
+
id: agent.id,
|
|
84
|
+
name: agent.name,
|
|
85
|
+
reputationScore,
|
|
86
|
+
badges,
|
|
87
|
+
verified: agent.verified,
|
|
88
|
+
subscriptionTier: agent.subscriptionTier,
|
|
89
|
+
stats: {
|
|
90
|
+
tasksCompleted: agent.stats.tasksCompleted,
|
|
91
|
+
totalEarned: agent.stats.totalEarned,
|
|
92
|
+
successRate: agent.stats.successRate,
|
|
93
|
+
disputeCount: agent.stats.disputeCount,
|
|
94
|
+
disputeRate: agent.stats.disputeRate,
|
|
95
|
+
avgCompletionTime: agent.stats.avgCompletionTime,
|
|
96
|
+
},
|
|
97
|
+
accountAgeDays: Math.floor((Date.now() - agent.createdAt.getTime()) / (1000 * 60 * 60 * 24)),
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
agent_search: {
|
|
103
|
+
description: 'Search for agents by skill, verified status, or minimum task count. Use this to find agents to hire for tasks.',
|
|
104
|
+
inputSchema: agentSearchSchema,
|
|
105
|
+
handler: async (input) => {
|
|
106
|
+
const agents = await searchAgents({
|
|
107
|
+
skill: input.skill,
|
|
108
|
+
verified: input.verified,
|
|
109
|
+
minTasksCompleted: input.minTasksCompleted,
|
|
110
|
+
limit: input.limit,
|
|
111
|
+
});
|
|
112
|
+
if (agents.length === 0) {
|
|
113
|
+
return {
|
|
114
|
+
success: true,
|
|
115
|
+
message: 'No agents found matching your criteria.',
|
|
116
|
+
agents: [],
|
|
117
|
+
count: 0,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
// Sort by reputation score (descending)
|
|
121
|
+
const agentsWithScores = agents.map(agent => ({
|
|
122
|
+
id: agent.id,
|
|
123
|
+
name: agent.name,
|
|
124
|
+
description: agent.description,
|
|
125
|
+
skills: agent.skills,
|
|
126
|
+
verified: agent.verified,
|
|
127
|
+
subscriptionTier: agent.subscriptionTier,
|
|
128
|
+
reputationScore: calculateReputationScore(agent),
|
|
129
|
+
stats: {
|
|
130
|
+
tasksCompleted: agent.stats.tasksCompleted,
|
|
131
|
+
totalEarned: agent.stats.totalEarned,
|
|
132
|
+
disputeRate: agent.stats.disputeRate,
|
|
133
|
+
},
|
|
134
|
+
})).sort((a, b) => b.reputationScore - a.reputationScore);
|
|
135
|
+
return {
|
|
136
|
+
success: true,
|
|
137
|
+
agents: agentsWithScores,
|
|
138
|
+
count: agentsWithScores.length,
|
|
139
|
+
};
|
|
140
|
+
},
|
|
141
|
+
},
|
|
142
|
+
agent_balance: {
|
|
143
|
+
description: 'Check your current balance. Requires your API key for authentication.',
|
|
144
|
+
inputSchema: agentBalanceSchema,
|
|
145
|
+
handler: async (input) => {
|
|
146
|
+
// Validate API key
|
|
147
|
+
const isValid = await validateApiKey(input.agentId, input.apiKey);
|
|
148
|
+
if (!isValid) {
|
|
149
|
+
return {
|
|
150
|
+
success: false,
|
|
151
|
+
error: 'Invalid API key',
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
const balance = await getBalance(input.agentId);
|
|
155
|
+
const agent = await getAgent(input.agentId);
|
|
156
|
+
return {
|
|
157
|
+
success: true,
|
|
158
|
+
agentId: input.agentId,
|
|
159
|
+
balance,
|
|
160
|
+
currency: 'USD', // Default currency
|
|
161
|
+
totalEarned: agent?.stats.totalEarned ?? 0,
|
|
162
|
+
};
|
|
163
|
+
},
|
|
164
|
+
},
|
|
165
|
+
withdraw_request: {
|
|
166
|
+
description: 'Request a withdrawal of your balance. Admin will process it manually via PayPal/Venmo.',
|
|
167
|
+
inputSchema: withdrawRequestSchema,
|
|
168
|
+
handler: async (input) => {
|
|
169
|
+
// Validate API key
|
|
170
|
+
const isValid = await validateApiKey(input.agentId, input.apiKey);
|
|
171
|
+
if (!isValid) {
|
|
172
|
+
return {
|
|
173
|
+
success: false,
|
|
174
|
+
error: 'Invalid API key',
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
try {
|
|
178
|
+
const withdrawal = await createWithdrawal(input.agentId, input.amount, input.currency, input.paymentMethod);
|
|
179
|
+
return {
|
|
180
|
+
success: true,
|
|
181
|
+
message: `Withdrawal request created. We'll process it within 24-48 hours.`,
|
|
182
|
+
withdrawal: {
|
|
183
|
+
id: withdrawal.id,
|
|
184
|
+
amount: withdrawal.amount,
|
|
185
|
+
currency: withdrawal.currency,
|
|
186
|
+
status: withdrawal.status,
|
|
187
|
+
paymentMethod: withdrawal.paymentMethod,
|
|
188
|
+
requestedAt: withdrawal.requestedAt.toISOString(),
|
|
189
|
+
},
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
catch (error) {
|
|
193
|
+
return {
|
|
194
|
+
success: false,
|
|
195
|
+
error: error instanceof Error ? error.message : 'Failed to create withdrawal',
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
},
|
|
199
|
+
},
|
|
200
|
+
};
|