@agentwonderland/mcp 0.1.14 → 0.1.15

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/tools/run.js CHANGED
@@ -1,10 +1,34 @@
1
1
  import { z } from "zod";
2
2
  import { apiGet, apiPost, apiPostWithPayment } from "../core/api-client.js";
3
3
  import { uploadLocalFiles } from "../core/file-upload.js";
4
- import { getConfiguredMethods, hasWalletConfigured } from "../core/payments.js";
4
+ import { getConfiguredMethods, hasWalletConfigured, getWalletAddress } from "../core/payments.js";
5
5
  import { requiresSpendConfirmation, getDefaultTipAmount } from "../core/config.js";
6
6
  import { formatRunResult } from "../core/formatters.js";
7
7
  import { storeFeedbackToken } from "./_token-cache.js";
8
+ const POLL_INTERVAL_MS = 3000;
9
+ const POLL_MAX_MS = 120000; // 2 minutes
10
+ async function pollJobUntilDone(jobId, agentName) {
11
+ const deadline = Date.now() + POLL_MAX_MS;
12
+ const walletAddress = await getWalletAddress();
13
+ const walletParam = walletAddress ? `?wallet=${walletAddress}` : "";
14
+ while (Date.now() < deadline) {
15
+ await new Promise((r) => setTimeout(r, POLL_INTERVAL_MS));
16
+ try {
17
+ const job = await apiGet(`/jobs/${jobId}${walletParam}`);
18
+ if (job.status === "completed") {
19
+ return { status: "completed", output: job.output };
20
+ }
21
+ if (job.status === "failed") {
22
+ return { status: "failed", output: job.output, error_code: job.error_code };
23
+ }
24
+ // Still processing — continue polling
25
+ }
26
+ catch {
27
+ // Ignore poll errors, keep trying until deadline
28
+ }
29
+ }
30
+ return { status: "failed", error_code: "POLL_TIMEOUT" };
31
+ }
8
32
  function text(t) {
9
33
  return { content: [{ type: "text", text: t }] };
10
34
  }
@@ -99,6 +123,38 @@ export function registerRunTools(server) {
99
123
  }
100
124
  const actualCost = result.cost;
101
125
  const status = result.status;
126
+ // Async agent — poll until complete
127
+ if (status === "processing") {
128
+ const pollResult = await pollJobUntilDone(jobId, agentName);
129
+ if (pollResult.status === "completed") {
130
+ const asyncFormatted = formatRunResult({
131
+ ...result,
132
+ status: "success",
133
+ output: pollResult.output,
134
+ }, { paymentMethod: method ?? getConfiguredMethods()[0] });
135
+ if (result.feedback_token) {
136
+ storeFeedbackToken(jobId, result.feedback_token, resultAgentId);
137
+ }
138
+ const asyncCostLine = actualCost != null ? `Paid $${actualCost.toFixed(actualCost < 0.01 ? 4 : 2)}.` : "";
139
+ const asyncFeedbackAsk = [
140
+ `IMPORTANT: After presenting the result above, you MUST ask the user:`,
141
+ `"${asyncCostLine} Was this result helpful? I can rate it (1-5 stars) or tip the builder for you."`,
142
+ "",
143
+ `If the user wants to rate: rate_agent({ job_id: "${jobId}", rating: <1-5>, comment: "..." })`,
144
+ `If the user wants to tip: tip_agent({ job_id: "${jobId}", agent_id: "${resultAgentId}", amount: 0.25 })`,
145
+ `To save for later: favorite_agent({ agent_id: "${resultAgentId}" })`,
146
+ ].join("\n");
147
+ return multiText(uploadSummary ? `${uploadSummary}\n\n${asyncFormatted}` : asyncFormatted, asyncFeedbackAsk);
148
+ }
149
+ // Async agent failed
150
+ const failedFormatted = formatRunResult({
151
+ ...result,
152
+ status: "failed",
153
+ output: pollResult.output,
154
+ error_code: pollResult.error_code,
155
+ }, { paymentMethod: method ?? getConfiguredMethods()[0] });
156
+ return multiText(uploadSummary ? `${uploadSummary}\n\n${failedFormatted}` : failedFormatted, "The agent execution failed. A refund has been initiated automatically.");
157
+ }
102
158
  // Auto-tip if configured and run succeeded
103
159
  const defaultTip = getDefaultTipAmount();
104
160
  let tipLine = "";
@@ -1,10 +1,33 @@
1
1
  import { z } from "zod";
2
2
  import { apiGet, apiPost, apiPostWithPayment } from "../core/api-client.js";
3
- import { hasWalletConfigured, getConfiguredMethods, getAcceptedPaymentMethods, } from "../core/payments.js";
3
+ import { hasWalletConfigured, getConfiguredMethods, getAcceptedPaymentMethods, getWalletAddress, } from "../core/payments.js";
4
4
  import { requiresSpendConfirmation, getDefaultTipAmount } from "../core/config.js";
5
5
  import { agentList, formatRunResult } from "../core/formatters.js";
6
6
  import { uploadLocalFiles } from "../core/file-upload.js";
7
7
  import { storeFeedbackToken } from "./_token-cache.js";
8
+ const POLL_INTERVAL_MS = 3000;
9
+ const POLL_MAX_MS = 120000;
10
+ async function pollSolveJob(jobId) {
11
+ const deadline = Date.now() + POLL_MAX_MS;
12
+ const walletAddress = await getWalletAddress();
13
+ const walletParam = walletAddress ? `?wallet=${walletAddress}` : "";
14
+ while (Date.now() < deadline) {
15
+ await new Promise((r) => setTimeout(r, POLL_INTERVAL_MS));
16
+ try {
17
+ const job = await apiGet(`/jobs/${jobId}${walletParam}`);
18
+ if (job.status === "completed") {
19
+ return { status: "completed", output: job.output };
20
+ }
21
+ if (job.status === "failed") {
22
+ return { status: "failed", output: job.output, error_code: job.error_code };
23
+ }
24
+ }
25
+ catch {
26
+ // Ignore poll errors, keep trying
27
+ }
28
+ }
29
+ return { status: "failed", error_code: "POLL_TIMEOUT" };
30
+ }
8
31
  function text(t) {
9
32
  return { content: [{ type: "text", text: t }] };
10
33
  }
@@ -171,9 +194,46 @@ export function registerSolveTools(server) {
171
194
  }
172
195
  const jobId = result.job_id ?? "";
173
196
  const agentId2 = result.agent_id ?? selected.id;
197
+ const status = result.status;
174
198
  if (result.feedback_token) {
175
199
  storeFeedbackToken(jobId, result.feedback_token, agentId2);
176
200
  }
201
+ // Async agent — poll until complete
202
+ if (status === "processing") {
203
+ const pollResult = await pollSolveJob(jobId);
204
+ if (pollResult.status === "completed") {
205
+ const asyncFormatted = formatRunResult({
206
+ ...result,
207
+ status: "success",
208
+ output: pollResult.output,
209
+ }, { paymentMethod: method });
210
+ const asyncOutput = [
211
+ discovery,
212
+ "",
213
+ `Running ${selected.name} — best match`,
214
+ `Estimated cost: $${estimatedCost.toFixed(4)}`,
215
+ "",
216
+ asyncFormatted,
217
+ ].join("\n");
218
+ const asyncCost = result.cost;
219
+ return multiText(asyncOutput, feedbackAsk(jobId, agentId2, asyncCost, ""));
220
+ }
221
+ // Async agent failed
222
+ const failedFormatted = formatRunResult({
223
+ ...result,
224
+ status: "failed",
225
+ output: pollResult.output,
226
+ error_code: pollResult.error_code,
227
+ }, { paymentMethod: method });
228
+ const failedOutput = [
229
+ discovery,
230
+ "",
231
+ `Running ${selected.name} — best match`,
232
+ "",
233
+ failedFormatted,
234
+ ].join("\n");
235
+ return multiText(failedOutput, "The agent execution failed. A refund has been initiated automatically.");
236
+ }
177
237
  const actualCost = result.cost;
178
238
  const tipMsg = result.feedback_token ? await autoTip(jobId, agentId2, selected.name ?? "", result.feedback_token) : "";
179
239
  const output = [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentwonderland/mcp",
3
- "version": "0.1.14",
3
+ "version": "0.1.15",
4
4
  "type": "module",
5
5
  "description": "MCP server for the Agent Wonderland AI agent marketplace",
6
6
  "bin": {
package/src/tools/run.ts CHANGED
@@ -2,11 +2,46 @@ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
2
  import { z } from "zod";
3
3
  import { apiGet, apiPost, apiPostWithPayment } from "../core/api-client.js";
4
4
  import { uploadLocalFiles } from "../core/file-upload.js";
5
- import { getConfiguredMethods, hasWalletConfigured } from "../core/payments.js";
5
+ import { getConfiguredMethods, hasWalletConfigured, getWalletAddress } from "../core/payments.js";
6
6
  import { requiresSpendConfirmation, getDefaultTipAmount } from "../core/config.js";
7
7
  import { formatRunResult } from "../core/formatters.js";
8
8
  import { storeFeedbackToken, getFeedbackToken } from "./_token-cache.js";
9
9
 
10
+ const POLL_INTERVAL_MS = 3000;
11
+ const POLL_MAX_MS = 120000; // 2 minutes
12
+
13
+ async function pollJobUntilDone(
14
+ jobId: string,
15
+ agentName: string,
16
+ ): Promise<{ status: string; output?: unknown; error_code?: string }> {
17
+ const deadline = Date.now() + POLL_MAX_MS;
18
+ const walletAddress = await getWalletAddress();
19
+ const walletParam = walletAddress ? `?wallet=${walletAddress}` : "";
20
+
21
+ while (Date.now() < deadline) {
22
+ await new Promise((r) => setTimeout(r, POLL_INTERVAL_MS));
23
+ try {
24
+ const job = await apiGet<{
25
+ status: string;
26
+ output?: unknown;
27
+ error_code?: string;
28
+ }>(`/jobs/${jobId}${walletParam}`);
29
+
30
+ if (job.status === "completed") {
31
+ return { status: "completed", output: job.output };
32
+ }
33
+ if (job.status === "failed") {
34
+ return { status: "failed", output: job.output, error_code: job.error_code };
35
+ }
36
+ // Still processing — continue polling
37
+ } catch {
38
+ // Ignore poll errors, keep trying until deadline
39
+ }
40
+ }
41
+
42
+ return { status: "failed", error_code: "POLL_TIMEOUT" };
43
+ }
44
+
10
45
  function text(t: string) {
11
46
  return { content: [{ type: "text" as const, text: t }] };
12
47
  }
@@ -127,6 +162,50 @@ export function registerRunTools(server: McpServer): void {
127
162
  const actualCost = result.cost as number | undefined;
128
163
  const status = result.status as string;
129
164
 
165
+ // Async agent — poll until complete
166
+ if (status === "processing") {
167
+ const pollResult = await pollJobUntilDone(jobId, agentName);
168
+ if (pollResult.status === "completed") {
169
+ const asyncFormatted = formatRunResult({
170
+ ...result,
171
+ status: "success",
172
+ output: pollResult.output,
173
+ }, { paymentMethod: method ?? getConfiguredMethods()[0] });
174
+
175
+ if (result.feedback_token) {
176
+ storeFeedbackToken(jobId, result.feedback_token as string, resultAgentId);
177
+ }
178
+
179
+ const asyncCostLine = actualCost != null ? `Paid $${actualCost.toFixed(actualCost < 0.01 ? 4 : 2)}.` : "";
180
+ const asyncFeedbackAsk = [
181
+ `IMPORTANT: After presenting the result above, you MUST ask the user:`,
182
+ `"${asyncCostLine} Was this result helpful? I can rate it (1-5 stars) or tip the builder for you."`,
183
+ "",
184
+ `If the user wants to rate: rate_agent({ job_id: "${jobId}", rating: <1-5>, comment: "..." })`,
185
+ `If the user wants to tip: tip_agent({ job_id: "${jobId}", agent_id: "${resultAgentId}", amount: 0.25 })`,
186
+ `To save for later: favorite_agent({ agent_id: "${resultAgentId}" })`,
187
+ ].join("\n");
188
+
189
+ return multiText(
190
+ uploadSummary ? `${uploadSummary}\n\n${asyncFormatted}` : asyncFormatted,
191
+ asyncFeedbackAsk,
192
+ );
193
+ }
194
+
195
+ // Async agent failed
196
+ const failedFormatted = formatRunResult({
197
+ ...result,
198
+ status: "failed",
199
+ output: pollResult.output,
200
+ error_code: pollResult.error_code,
201
+ }, { paymentMethod: method ?? getConfiguredMethods()[0] });
202
+
203
+ return multiText(
204
+ uploadSummary ? `${uploadSummary}\n\n${failedFormatted}` : failedFormatted,
205
+ "The agent execution failed. A refund has been initiated automatically.",
206
+ );
207
+ }
208
+
130
209
  // Auto-tip if configured and run succeeded
131
210
  const defaultTip = getDefaultTipAmount();
132
211
  let tipLine = "";
@@ -5,6 +5,7 @@ import {
5
5
  hasWalletConfigured,
6
6
  getConfiguredMethods,
7
7
  getAcceptedPaymentMethods,
8
+ getWalletAddress,
8
9
  } from "../core/payments.js";
9
10
  import { requiresSpendConfirmation, getDefaultTipAmount } from "../core/config.js";
10
11
  import { agentList, formatRunResult } from "../core/formatters.js";
@@ -12,6 +13,39 @@ import { uploadLocalFiles } from "../core/file-upload.js";
12
13
  import type { AgentRecord } from "../core/types.js";
13
14
  import { storeFeedbackToken } from "./_token-cache.js";
14
15
 
16
+ const POLL_INTERVAL_MS = 3000;
17
+ const POLL_MAX_MS = 120000;
18
+
19
+ async function pollSolveJob(
20
+ jobId: string,
21
+ ): Promise<{ status: string; output?: unknown; error_code?: string }> {
22
+ const deadline = Date.now() + POLL_MAX_MS;
23
+ const walletAddress = await getWalletAddress();
24
+ const walletParam = walletAddress ? `?wallet=${walletAddress}` : "";
25
+
26
+ while (Date.now() < deadline) {
27
+ await new Promise((r) => setTimeout(r, POLL_INTERVAL_MS));
28
+ try {
29
+ const job = await apiGet<{
30
+ status: string;
31
+ output?: unknown;
32
+ error_code?: string;
33
+ }>(`/jobs/${jobId}${walletParam}`);
34
+
35
+ if (job.status === "completed") {
36
+ return { status: "completed", output: job.output };
37
+ }
38
+ if (job.status === "failed") {
39
+ return { status: "failed", output: job.output, error_code: job.error_code };
40
+ }
41
+ } catch {
42
+ // Ignore poll errors, keep trying
43
+ }
44
+ }
45
+
46
+ return { status: "failed", error_code: "POLL_TIMEOUT" };
47
+ }
48
+
15
49
  function text(t: string) {
16
50
  return { content: [{ type: "text" as const, text: t }] };
17
51
  }
@@ -204,11 +238,54 @@ export function registerSolveTools(server: McpServer): void {
204
238
 
205
239
  const jobId = (result as Record<string, unknown>).job_id as string ?? "";
206
240
  const agentId2 = (result as Record<string, unknown>).agent_id as string ?? selected.id;
241
+ const status = result.status as string;
207
242
 
208
243
  if (result.feedback_token) {
209
244
  storeFeedbackToken(jobId, result.feedback_token as string, agentId2);
210
245
  }
211
246
 
247
+ // Async agent — poll until complete
248
+ if (status === "processing") {
249
+ const pollResult = await pollSolveJob(jobId);
250
+ if (pollResult.status === "completed") {
251
+ const asyncFormatted = formatRunResult({
252
+ ...result,
253
+ status: "success",
254
+ output: pollResult.output,
255
+ }, { paymentMethod: method });
256
+
257
+ const asyncOutput = [
258
+ discovery,
259
+ "",
260
+ `Running ${selected.name} — best match`,
261
+ `Estimated cost: $${estimatedCost.toFixed(4)}`,
262
+ "",
263
+ asyncFormatted,
264
+ ].join("\n");
265
+
266
+ const asyncCost = (result as Record<string, unknown>).cost as number | undefined;
267
+ return multiText(asyncOutput, feedbackAsk(jobId, agentId2, asyncCost, ""));
268
+ }
269
+
270
+ // Async agent failed
271
+ const failedFormatted = formatRunResult({
272
+ ...result,
273
+ status: "failed",
274
+ output: pollResult.output,
275
+ error_code: pollResult.error_code,
276
+ }, { paymentMethod: method });
277
+
278
+ const failedOutput = [
279
+ discovery,
280
+ "",
281
+ `Running ${selected.name} — best match`,
282
+ "",
283
+ failedFormatted,
284
+ ].join("\n");
285
+
286
+ return multiText(failedOutput, "The agent execution failed. A refund has been initiated automatically.");
287
+ }
288
+
212
289
  const actualCost = (result as Record<string, unknown>).cost as number | undefined;
213
290
  const tipMsg = result.feedback_token ? await autoTip(jobId, agentId2, selected.name ?? "", result.feedback_token as string) : "";
214
291