@agentwonderland/mcp 0.1.23 → 0.1.25

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.
Files changed (95) hide show
  1. package/dist/core/__tests__/amount-utils.test.d.ts +1 -0
  2. package/dist/core/__tests__/amount-utils.test.js +11 -0
  3. package/dist/core/__tests__/card-setup.test.d.ts +1 -0
  4. package/dist/core/__tests__/card-setup.test.js +99 -0
  5. package/dist/core/__tests__/formatters.test.d.ts +1 -0
  6. package/dist/core/__tests__/formatters.test.js +15 -0
  7. package/dist/core/__tests__/passes.test.d.ts +1 -0
  8. package/dist/core/__tests__/passes.test.js +82 -0
  9. package/dist/core/__tests__/payments.test.d.ts +1 -0
  10. package/dist/core/__tests__/payments.test.js +101 -0
  11. package/dist/core/__tests__/principal.test.d.ts +1 -0
  12. package/dist/core/__tests__/principal.test.js +67 -0
  13. package/dist/core/__tests__/spend-policy.test.d.ts +1 -0
  14. package/dist/core/__tests__/spend-policy.test.js +40 -0
  15. package/dist/core/amount-utils.d.ts +1 -0
  16. package/dist/core/amount-utils.js +4 -0
  17. package/dist/core/api-client.d.ts +9 -4
  18. package/dist/core/api-client.js +52 -22
  19. package/dist/core/base-charge.js +3 -2
  20. package/dist/core/card-setup.d.ts +20 -13
  21. package/dist/core/card-setup.js +85 -29
  22. package/dist/core/config.d.ts +22 -0
  23. package/dist/core/config.js +46 -2
  24. package/dist/core/formatters.d.ts +4 -3
  25. package/dist/core/formatters.js +10 -8
  26. package/dist/core/index.d.ts +2 -0
  27. package/dist/core/index.js +2 -0
  28. package/dist/core/ows-adapter.d.ts +10 -2
  29. package/dist/core/ows-adapter.js +54 -10
  30. package/dist/core/passes.d.ts +40 -0
  31. package/dist/core/passes.js +32 -0
  32. package/dist/core/payments.d.ts +8 -0
  33. package/dist/core/payments.js +111 -17
  34. package/dist/core/principal.d.ts +2 -0
  35. package/dist/core/principal.js +109 -0
  36. package/dist/core/solana-charge.d.ts +9 -0
  37. package/dist/core/solana-charge.js +96 -0
  38. package/dist/core/spend-policy.d.ts +12 -0
  39. package/dist/core/spend-policy.js +53 -0
  40. package/dist/core/types.d.ts +11 -2
  41. package/dist/index.js +11 -3
  42. package/dist/prompts/index.js +4 -2
  43. package/dist/resources/agents.js +1 -1
  44. package/dist/resources/wallet.js +8 -1
  45. package/dist/tools/__tests__/_payment-confirmation.test.d.ts +1 -0
  46. package/dist/tools/__tests__/_payment-confirmation.test.js +30 -0
  47. package/dist/tools/_payment-confirmation.d.ts +6 -0
  48. package/dist/tools/_payment-confirmation.js +28 -0
  49. package/dist/tools/agent-info.js +16 -2
  50. package/dist/tools/favorites.js +1 -1
  51. package/dist/tools/index.d.ts +1 -0
  52. package/dist/tools/index.js +1 -0
  53. package/dist/tools/observability.d.ts +2 -0
  54. package/dist/tools/observability.js +20 -0
  55. package/dist/tools/passes.d.ts +2 -0
  56. package/dist/tools/passes.js +157 -0
  57. package/dist/tools/run.js +127 -53
  58. package/dist/tools/solve.js +115 -51
  59. package/dist/tools/wallet.js +110 -59
  60. package/package.json +3 -1
  61. package/src/core/__tests__/amount-utils.test.ts +13 -0
  62. package/src/core/__tests__/card-setup.test.ts +118 -0
  63. package/src/core/__tests__/formatters.test.ts +17 -0
  64. package/src/core/__tests__/passes.test.ts +94 -0
  65. package/src/core/__tests__/payments.test.ts +122 -0
  66. package/src/core/__tests__/principal.test.ts +87 -0
  67. package/src/core/__tests__/spend-policy.test.ts +58 -0
  68. package/src/core/amount-utils.ts +5 -0
  69. package/src/core/api-client.ts +70 -23
  70. package/src/core/base-charge.ts +3 -2
  71. package/src/core/card-setup.ts +109 -34
  72. package/src/core/config.ts +74 -3
  73. package/src/core/formatters.ts +13 -9
  74. package/src/core/index.ts +2 -0
  75. package/src/core/ows-adapter.ts +74 -8
  76. package/src/core/passes.ts +74 -0
  77. package/src/core/payments.ts +130 -17
  78. package/src/core/principal.ts +128 -0
  79. package/src/core/solana-charge.ts +150 -0
  80. package/src/core/spend-policy.ts +69 -0
  81. package/src/core/types.ts +11 -2
  82. package/src/index.ts +11 -3
  83. package/src/prompts/index.ts +4 -2
  84. package/src/resources/agents.ts +1 -1
  85. package/src/resources/wallet.ts +8 -1
  86. package/src/tools/__tests__/_payment-confirmation.test.ts +45 -0
  87. package/src/tools/_payment-confirmation.ts +52 -0
  88. package/src/tools/agent-info.ts +25 -2
  89. package/src/tools/favorites.ts +1 -4
  90. package/src/tools/index.ts +1 -0
  91. package/src/tools/observability.ts +43 -0
  92. package/src/tools/passes.ts +228 -0
  93. package/src/tools/run.ts +174 -57
  94. package/src/tools/solve.ts +147 -59
  95. package/src/tools/wallet.ts +132 -62
package/src/tools/run.ts CHANGED
@@ -2,18 +2,36 @@ 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, getWalletAddress } from "../core/payments.js";
5
+ import {
6
+ formatCreditPackOffer,
7
+ getActiveCreditPack,
8
+ getCreditPackInventory,
9
+ getCreditPackProgram,
10
+ } from "../core/passes.js";
11
+ import {
12
+ getCompatiblePaymentMethods,
13
+ getConfiguredMethods,
14
+ hasWalletConfigured,
15
+ getWalletAddress,
16
+ normalizePaymentMethod,
17
+ } from "../core/payments.js";
6
18
  import { requiresSpendConfirmation, getDefaultTipAmount } from "../core/config.js";
7
19
  import { formatRunResult } from "../core/formatters.js";
8
- import { storeFeedbackToken, getFeedbackToken } from "./_token-cache.js";
9
- import { initiateCardSetup, formatCardSetupBlocks } from "../core/card-setup.js";
20
+ import { canSpend, recordSpend, requiresPolicyConfirmation } from "../core/spend-policy.js";
21
+ import { storeFeedbackToken } from "./_token-cache.js";
22
+ import { getOrCreatePendingCardSetup, formatCardSetupBlocks } from "../core/card-setup.js";
23
+ import {
24
+ formatPaymentLabel,
25
+ formatRunConfirmationCommand,
26
+ resolveConfirmationMethod,
27
+ } from "./_payment-confirmation.js";
28
+ import type { AgentRecord } from "../core/types.js";
10
29
 
11
30
  const POLL_INTERVAL_MS = 3000;
12
- const POLL_MAX_MS = 120000; // 2 minutes
31
+ const POLL_MAX_MS = 120000;
13
32
 
14
33
  async function pollJobUntilDone(
15
34
  jobId: string,
16
- agentName: string,
17
35
  ): Promise<{ status: string; output?: unknown; error_code?: string }> {
18
36
  const deadline = Date.now() + POLL_MAX_MS;
19
37
  const walletAddress = await getWalletAddress();
@@ -34,9 +52,8 @@ async function pollJobUntilDone(
34
52
  if (job.status === "failed") {
35
53
  return { status: "failed", output: job.output, error_code: job.error_code };
36
54
  }
37
- // Still processing — continue polling
38
55
  } catch {
39
- // Ignore poll errors, keep trying until deadline
56
+ // Ignore poll errors until timeout.
40
57
  }
41
58
  }
42
59
 
@@ -51,71 +68,130 @@ function multiText(...blocks: string[]) {
51
68
  return { content: blocks.map((t) => ({ type: "text" as const, text: t })) };
52
69
  }
53
70
 
54
- // Pending confirmations: agent_id → { agent, input, method }
55
71
  const pendingRuns = new Map<string, {
56
72
  agent: { id: string; name: string; price: number };
57
73
  input: Record<string, unknown>;
58
74
  method?: string;
59
75
  }>();
60
76
 
77
+ function buildCreditPackOfferLines(agent: AgentRecord): string[] {
78
+ const program = getCreditPackProgram(agent);
79
+ if (!program?.packs?.length) return [];
80
+
81
+ return [
82
+ "Discounted credit packs:",
83
+ ...program.packs.map((pack) => formatCreditPackOffer({
84
+ pack_id: pack.key ?? "",
85
+ label: pack.name ?? pack.key ?? "Credit Pack",
86
+ included_units: pack.included_units ?? 0,
87
+ price_usd: pack.price_usd ?? "0.00",
88
+ effective_price_per_unit_usd: (pack.included_units ?? 0) > 0 && pack.price_usd
89
+ ? (Number(pack.price_usd) / (pack.included_units ?? 1)).toFixed(6)
90
+ : undefined,
91
+ })).map((line) => ` ${line}`),
92
+ ` Buy one with buy_agent_credit_pack({ agent_id: "${agent.id}", pack_id: "<pack_id>" })`,
93
+ ];
94
+ }
95
+
61
96
  export function registerRunTools(server: McpServer): void {
62
97
  server.tool(
63
98
  "run_agent",
64
- "Run an AI agent from the marketplace. Pays automatically via configured wallet. Returns the agent's output, cost, and job ID for tracking. If spending confirmation is enabled, first call returns a price quote — call again with confirmed: true to execute. Local file paths in the input (e.g. /Users/.../photo.jpg) are automatically uploaded to temporary storage and replaced with download URLs just pass the path directly, no base64 encoding needed.",
99
+ "Run an AI agent from the marketplace. Pays automatically via configured wallet. Returns the agent's output, cost, and job ID for tracking. If spending confirmation is enabled, first call returns a price quote — call again with confirmed: true to execute. Local file paths in the input (e.g. /Users/.../photo.jpg) are automatically uploaded to temporary storage and replaced with download URLs before execution.",
65
100
  {
66
101
  agent_id: z.string().describe("Agent ID (UUID, slug, or name)"),
67
102
  input: z.record(z.unknown()).describe("Input payload for the agent"),
68
- pay_with: z.string().optional().describe("Payment method — wallet ID, chain name (tempo, base, etc.), or 'card'. Auto-detected if omitted."),
103
+ pay_with: z.string().trim().min(1).describe("Required payment method — wallet ID, chain name (tempo, base, etc.), or 'card'. Use wallet_status to see configured options."),
69
104
  confirmed: z.boolean().optional().describe("Set to true to confirm spending after seeing the price quote."),
70
105
  },
71
106
  async ({ agent_id, input, pay_with, confirmed }) => {
72
107
  if (!hasWalletConfigured()) {
73
108
  try {
74
- const { qr, url } = await initiateCardSetup();
75
- const blocks = formatCardSetupBlocks(qr, url);
76
- return multiText(...blocks);
109
+ const { url } = await getOrCreatePendingCardSetup();
110
+ return multiText(...formatCardSetupBlocks(url));
77
111
  } catch {
78
112
  return text(
79
113
  "No payment method configured.\n\n" +
80
114
  "To add a credit card: wallet_setup({ action: \"add-card\" })\n" +
81
- "To use crypto: wallet_setup({ action: \"create\" })"
115
+ "To use crypto: wallet_setup({ action: \"create\" })",
82
116
  );
83
117
  }
84
118
  }
85
119
 
86
- // Resolve agent and fetch details
87
- let agent: { id: string; name?: string; pricePer1kTokens?: string; successRate?: number };
120
+ let agent: AgentRecord;
88
121
  try {
89
- agent = await apiGet<typeof agent>(`/agents/${agent_id}`);
122
+ agent = await apiGet<AgentRecord>(`/agents/${agent_id}`);
90
123
  } catch {
91
124
  return text(`Agent "${agent_id}" not found. Use search_agents to find available agents.`);
92
125
  }
93
126
 
94
- const price = parseFloat(agent.pricePer1kTokens ?? "0.01");
127
+ const price = parseFloat(agent.pricePerRunUsd ?? "0.01");
95
128
  const agentName = agent.name ?? agent_id;
129
+ const creditPackInventory = await getCreditPackInventory(agent.id);
130
+ const activeCreditPack = getActiveCreditPack(creditPackInventory);
131
+ const compatibleMethods = getCompatiblePaymentMethods(agent, getConfiguredMethods());
132
+ const pending = pendingRuns.get(agent.id);
133
+ const requestedMethod = pay_with;
134
+ const normalizedRequestedMethod = normalizePaymentMethod(requestedMethod);
135
+
136
+ if (!normalizedRequestedMethod) {
137
+ return text(
138
+ `Payment method "${requestedMethod}" is not configured.\n\n` +
139
+ "Use wallet_status to review your current payment methods.",
140
+ );
141
+ }
96
142
 
97
- // Confirmation step: show price and wait for confirmed: true
98
- if (requiresSpendConfirmation() && !confirmed) {
143
+ if (!compatibleMethods.includes(normalizedRequestedMethod)) {
144
+ return text(
145
+ `This agent cannot be paid with "${requestedMethod}".\n\n` +
146
+ `Available payment methods for this agent: ${compatibleMethods.join(", ") || "none"}.\n` +
147
+ "Use get_agent to inspect the agent details or choose another payment method.",
148
+ );
149
+ }
150
+
151
+ const method = resolveConfirmationMethod(pay_with, pending?.method, compatibleMethods);
152
+ const spendCheckMethod = method ?? normalizedRequestedMethod;
153
+
154
+ if (!activeCreditPack) {
155
+ const spendCheck = canSpend({
156
+ method: spendCheckMethod,
157
+ amountUsd: price,
158
+ });
159
+ if (!spendCheck.ok) {
160
+ return text(spendCheck.message);
161
+ }
162
+ }
163
+
164
+ const needsPolicyConfirmation = !activeCreditPack && requiresPolicyConfirmation(spendCheckMethod, price);
165
+ if (!activeCreditPack && (requiresSpendConfirmation() || needsPolicyConfirmation) && !confirmed) {
99
166
  pendingRuns.set(agent.id, {
100
167
  agent: { id: agent.id, name: agentName, price },
101
168
  input,
102
- method: pay_with,
169
+ method,
103
170
  });
104
171
 
105
- return text([
172
+ const quoteLines = [
106
173
  `Ready to run ${agentName}`,
107
174
  "",
108
175
  ` Cost: $${price.toFixed(2)}`,
109
- ` Payment: ${pay_with ?? getConfiguredMethods()[0] ?? "auto"}`,
176
+ ` Payment: ${formatPaymentLabel(method)}`,
177
+ ];
178
+
179
+ const creditPackLines = buildCreditPackOfferLines(agent);
180
+ if (creditPackLines.length > 0) {
181
+ quoteLines.push("", ...creditPackLines);
182
+ }
183
+
184
+ quoteLines.push(
110
185
  "",
111
186
  "To proceed, call:",
112
- ` run_agent({ agent_id: "${agent.id}", input: <same>, confirmed: true })`,
187
+ formatRunConfirmationCommand(agent.id, method),
113
188
  "",
114
189
  "To cancel, do nothing.",
115
- ].join("\n"));
190
+ );
191
+
192
+ return text(quoteLines.join("\n"));
116
193
  }
117
194
 
118
- const method = pay_with;
119
195
  let processedInput: Record<string, unknown>;
120
196
  let uploadSummary = "";
121
197
  try {
@@ -123,30 +199,59 @@ export function registerRunTools(server: McpServer): void {
123
199
  processedInput = uploadResult.input;
124
200
  if (uploadResult.uploads.length > 0) {
125
201
  uploadSummary = uploadResult.uploads
126
- .map((u) => `Uploaded ${u.field}: ${u.originalPath} → ${u.url}`)
202
+ .map((upload) => `Uploaded ${upload.field}: ${upload.originalPath} → ${upload.url}`)
127
203
  .join("\n");
128
204
  }
129
205
  } catch (err) {
130
206
  const msg = err instanceof Error ? err.message : "File upload failed";
131
207
  return text(`Error: ${msg}`);
132
208
  }
209
+
133
210
  let result: Record<string, unknown>;
211
+ let usedPaidMethod = !activeCreditPack;
134
212
  try {
135
- result = await apiPostWithPayment<Record<string, unknown>>(
136
- `/agents/${agent.id}/run`,
137
- { input: processedInput },
138
- method,
139
- );
213
+ if (activeCreditPack) {
214
+ try {
215
+ result = await apiPost<Record<string, unknown>>(
216
+ `/agents/${agent.id}/run`,
217
+ { input: processedInput },
218
+ { ensureConsumerPrincipal: true },
219
+ );
220
+ } catch (packErr) {
221
+ const packApiErr = packErr as { status?: number };
222
+ if (packApiErr?.status !== 402) throw packErr;
223
+ result = await apiPostWithPayment<Record<string, unknown>>(
224
+ `/agents/${agent.id}/run`,
225
+ { input: processedInput },
226
+ method,
227
+ );
228
+ usedPaidMethod = true;
229
+ }
230
+ } else {
231
+ result = await apiPostWithPayment<Record<string, unknown>>(
232
+ `/agents/${agent.id}/run`,
233
+ { input: processedInput },
234
+ method,
235
+ );
236
+ }
237
+ if (usedPaidMethod) {
238
+ recordSpend(spendCheckMethod, price);
239
+ }
140
240
  } catch (err: unknown) {
141
241
  const apiErr = err as { status?: number; message?: string };
142
242
  if (apiErr?.status === 402) {
143
243
  const allMethods = getConfiguredMethods();
144
244
  const methodName = method ?? allMethods[0] ?? "auto";
245
+ const creditPackLines = buildCreditPackOfferLines(agent);
145
246
  return text(
146
- `Payment failed — "${methodName}" payment was rejected.\n\n` +
147
- "Check your payment method and try again.\n" +
148
- (allMethods.length > 0 ? `Configured methods: ${allMethods.join(", ")}\n` : "") +
149
- "Use wallet_status to check your current payment methods."
247
+ [
248
+ `Payment failed "${methodName}" payment was rejected.`,
249
+ "",
250
+ "Check your payment method and try again.",
251
+ ...(allMethods.length > 0 ? [`Configured methods: ${allMethods.join(", ")}`] : []),
252
+ "Use wallet_status to check your current payment methods.",
253
+ ...(creditPackLines.length > 0 ? ["", ...creditPackLines] : []),
254
+ ].join("\n"),
150
255
  );
151
256
  }
152
257
  const msg = apiErr?.message ?? "Failed to run agent";
@@ -156,7 +261,6 @@ export function registerRunTools(server: McpServer): void {
156
261
  return text(`Error: ${msg}`);
157
262
  }
158
263
 
159
- // Clean up pending confirmation
160
264
  pendingRuns.delete(agent.id);
161
265
 
162
266
  const formatted = formatRunResult(result, {
@@ -171,10 +275,10 @@ export function registerRunTools(server: McpServer): void {
171
275
 
172
276
  const actualCost = result.cost as number | undefined;
173
277
  const status = result.status as string;
278
+ const usedCreditPack = result.consumption_mode === "credit_pack";
174
279
 
175
- // Async agent — poll until complete
176
280
  if (status === "processing") {
177
- const pollResult = await pollJobUntilDone(jobId, agentName);
281
+ const pollResult = await pollJobUntilDone(jobId);
178
282
  if (pollResult.status === "completed") {
179
283
  const asyncFormatted = formatRunResult({
180
284
  ...result,
@@ -182,14 +286,15 @@ export function registerRunTools(server: McpServer): void {
182
286
  output: pollResult.output,
183
287
  }, { paymentMethod: method ?? getConfiguredMethods()[0] });
184
288
 
185
- if (result.feedback_token) {
186
- storeFeedbackToken(jobId, result.feedback_token as string, resultAgentId);
187
- }
289
+ const asyncSpendLine = usedCreditPack
290
+ ? "This run used your available credit pack."
291
+ : actualCost != null
292
+ ? `Paid $${actualCost.toFixed(actualCost < 0.01 ? 4 : 2)}.`
293
+ : "This run completed successfully.";
188
294
 
189
- const asyncCostLine = actualCost != null ? `Paid $${actualCost.toFixed(actualCost < 0.01 ? 4 : 2)}.` : "";
190
295
  const asyncFeedbackAsk = [
191
- `IMPORTANT: After presenting the result above, you MUST ask the user:`,
192
- `"${asyncCostLine} Was this result helpful? I can rate it (1-5 stars) or tip the builder for you."`,
296
+ "IMPORTANT: After presenting the result above, you MUST ask the user:",
297
+ `"${asyncSpendLine} Was this result helpful? I can rate it (1-5 stars) or tip the builder for you."`,
193
298
  "",
194
299
  `If the user wants to rate: rate_agent({ job_id: "${jobId}", rating: <1-5>, comment: "..." })`,
195
300
  `If the user wants to tip: tip_agent({ job_id: "${jobId}", agent_id: "${resultAgentId}", amount: 0.25 })`,
@@ -202,7 +307,6 @@ export function registerRunTools(server: McpServer): void {
202
307
  );
203
308
  }
204
309
 
205
- // Async agent failed
206
310
  const failedFormatted = formatRunResult({
207
311
  ...result,
208
312
  status: "failed",
@@ -212,11 +316,12 @@ export function registerRunTools(server: McpServer): void {
212
316
 
213
317
  return multiText(
214
318
  uploadSummary ? `${uploadSummary}\n\n${failedFormatted}` : failedFormatted,
215
- "The agent execution failed. A refund has been initiated automatically.",
319
+ usedCreditPack
320
+ ? "The agent execution failed and your reserved credit-pack unit was released automatically."
321
+ : "The agent execution failed. A refund has been initiated automatically.",
216
322
  );
217
323
  }
218
324
 
219
- // Auto-tip if configured and run succeeded
220
325
  const defaultTip = getDefaultTipAmount();
221
326
  let tipLine = "";
222
327
  if (status === "success" && defaultTip > 0 && result.feedback_token) {
@@ -236,20 +341,24 @@ export function registerRunTools(server: McpServer): void {
236
341
  if (status !== "success") {
237
342
  return multiText(
238
343
  uploadSummary ? `${uploadSummary}\n\n${formatted}` : formatted,
239
- "The agent execution failed. A refund has been initiated automatically.",
344
+ usedCreditPack
345
+ ? "The agent execution failed and your reserved credit-pack unit was released automatically."
346
+ : "The agent execution failed. A refund has been initiated automatically.",
240
347
  );
241
348
  }
242
349
 
243
- const costLine = actualCost != null ? `Paid $${actualCost.toFixed(actualCost < 0.01 ? 4 : 2)}.` : "";
350
+ const costLine = usedCreditPack
351
+ ? ""
352
+ : actualCost != null
353
+ ? `Paid $${actualCost.toFixed(actualCost < 0.01 ? 4 : 2)}.`
354
+ : "";
355
+ const spendLine = usedCreditPack ? "This run used your available credit pack." : (costLine || "This run completed successfully.");
244
356
 
245
- // Separate the feedback ask into its own content block so the LLM
246
- // surfaces it to the user as a distinct follow-up question, rather than
247
- // burying it inside a collapsed tool output.
248
357
  const feedbackAsk = [
249
- `--- Job ${jobId} | ${agentName} | ${costLine} ---`,
358
+ `--- Job ${jobId} | ${agentName} | ${usedCreditPack ? "covered by credit pack" : (costLine || "completed")} ---`,
250
359
  "",
251
- `IMPORTANT: After presenting the result above, you MUST ask the user:`,
252
- `"${costLine} Was this result helpful? I can rate it (1-5 stars) or tip the builder for you."`,
360
+ "IMPORTANT: After presenting the result above, you MUST ask the user:",
361
+ `"${spendLine} Was this result helpful? I can rate it (1-5 stars) or tip the builder for you."`,
253
362
  tipLine,
254
363
  "",
255
364
  `If the user wants to rate: rate_agent({ job_id: "${jobId}", rating: <1-5>, comment: "..." })`,
@@ -259,7 +368,15 @@ export function registerRunTools(server: McpServer): void {
259
368
  `To save for later: favorite_agent({ agent_id: "${resultAgentId}" })`,
260
369
  ].join("\n");
261
370
 
262
- return multiText(uploadSummary ? `${uploadSummary}\n\n${formatted}` : formatted, feedbackAsk);
371
+ const supplementalLines = !usedCreditPack
372
+ ? buildCreditPackOfferLines(agent)
373
+ : [];
374
+
375
+ const primaryBlock = uploadSummary ? `${uploadSummary}\n\n${formatted}` : formatted;
376
+ return multiText(
377
+ supplementalLines.length > 0 ? `${primaryBlock}\n\n${supplementalLines.join("\n")}` : primaryBlock,
378
+ feedbackAsk,
379
+ );
263
380
  },
264
381
  );
265
382
  }