@elisym/mcp 0.8.12 → 0.8.14

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/index.js CHANGED
@@ -1167,6 +1167,7 @@ function sanitizeField(input, maxLen) {
1167
1167
  }
1168
1168
  var CUSTOMER_HISTORY_FILENAME = ".customer-history.json";
1169
1169
  var MAX_HISTORY_ENTRIES = 500;
1170
+ var RESULT_PREVIEW_MAX_LEN = 1e4;
1170
1171
  var StatusSchema = z.enum(["completed", "failed", "timeout"]);
1171
1172
  var FeedbackSchema = z.enum(["positive", "negative"]);
1172
1173
  var CustomerJobEntrySchema = z.object({
@@ -1179,7 +1180,7 @@ var CustomerJobEntrySchema = z.object({
1179
1180
  status: StatusSchema,
1180
1181
  submittedAt: z.number().int().nonnegative(),
1181
1182
  completedAt: z.number().int().nonnegative(),
1182
- resultPreview: z.string().max(500).optional(),
1183
+ resultPreview: z.string().max(RESULT_PREVIEW_MAX_LEN).optional(),
1183
1184
  paymentSig: z.string().max(128).optional(),
1184
1185
  customerFeedback: FeedbackSchema.optional()
1185
1186
  }).strict();
@@ -1856,7 +1857,7 @@ ${sanitized.text}`);
1856
1857
  status: "completed",
1857
1858
  submittedAt,
1858
1859
  completedAt: Date.now(),
1859
- resultPreview: result.slice(0, 500),
1860
+ resultPreview: result.slice(0, RESULT_PREVIEW_MAX_LEN),
1860
1861
  paymentSig
1861
1862
  });
1862
1863
  const warningBlock = paymentWarnings.length > 0 ? `${paymentWarnings.join("\n")}
@@ -2015,7 +2016,7 @@ ${sanitized.text}`
2015
2016
  status: "completed",
2016
2017
  submittedAt,
2017
2018
  completedAt: Date.now(),
2018
- resultPreview: result.slice(0, 500),
2019
+ resultPreview: result.slice(0, RESULT_PREVIEW_MAX_LEN),
2019
2020
  paymentSig
2020
2021
  });
2021
2022
  const warningBlock = paymentWarnings.length > 0 ? `${paymentWarnings.join("\n")}
@@ -2336,7 +2337,7 @@ var GetIdentitySchema = z.object({});
2336
2337
  var discoveryTools = [
2337
2338
  defineTool({
2338
2339
  name: "search_agents",
2339
- description: "Search AI agents currently online on elisym. `capabilities` is a hard OR-filter of substring tokens from the user's request (never invent synonyms). `query` is optional re-ranking; omit if not needed. Offline agents are excluded by default - pass include_offline=true only when debugging.",
2340
+ description: "Search AI agents currently online on elisym. `capabilities` is a hard OR-filter of substring tokens from the user's request (never invent synonyms). `query` is optional re-ranking; omit if not needed. Offline agents are excluded by default - pass include_offline=true only when debugging. Results that match a saved contact are sorted to the top and annotated with `is_contact`, `last_worked_at`, `last_capability`, and `contact_note` - surface this to the user (e.g. \"already in your contacts, last used <date>\") so they can prefer providers they've worked with before.",
2340
2341
  schema: SearchAgentsSchema,
2341
2342
  async handler(ctx, input) {
2342
2343
  const { capabilities, query, max_price_lamports, include_offline, contacts_only } = input;
@@ -2344,25 +2345,27 @@ var discoveryTools = [
2344
2345
  return errorResult(`Too many capabilities (max ${MAX_CAPABILITIES})`);
2345
2346
  }
2346
2347
  const agent = ctx.active();
2347
- let lastWorkedAtByPubkey = /* @__PURE__ */ new Map();
2348
+ const contactByPubkey = /* @__PURE__ */ new Map();
2349
+ if (agent.agentDir) {
2350
+ const data = await readContacts(agent.agentDir);
2351
+ for (const contact of data.contacts) {
2352
+ contactByPubkey.set(contact.pubkey, contact);
2353
+ }
2354
+ }
2348
2355
  if (contacts_only) {
2349
2356
  if (!agent.agentDir) {
2350
2357
  return textResult(
2351
2358
  "contacts_only=true requires a persistent agent (no on-disk directory for the active agent)."
2352
2359
  );
2353
2360
  }
2354
- const data = await readContacts(agent.agentDir);
2355
- if (data.contacts.length === 0) {
2361
+ if (contactByPubkey.size === 0) {
2356
2362
  return textResult(
2357
2363
  "No contacts saved yet. Use add_contact (or rate a job positively with submit_feedback and then add_contact) before searching with contacts_only=true."
2358
2364
  );
2359
2365
  }
2360
- lastWorkedAtByPubkey = new Map(
2361
- data.contacts.map((contact) => [contact.pubkey, contact.lastJobAt ?? contact.addedAt])
2362
- );
2363
2366
  }
2364
2367
  const agents = await agent.client.discovery.fetchAgents(agent.network);
2365
- let filtered = contacts_only ? agents.filter((a) => lastWorkedAtByPubkey.has(a.pubkey)) : agents;
2368
+ let filtered = contacts_only ? agents.filter((a) => contactByPubkey.has(a.pubkey)) : agents;
2366
2369
  filtered = filtered.filter(
2367
2370
  (a) => a.cards.some(
2368
2371
  (card) => capabilities.some(
@@ -2405,10 +2408,28 @@ var discoveryTools = [
2405
2408
  hits++;
2406
2409
  }
2407
2410
  }
2408
- return { agent: a, score: hits };
2411
+ const contactBoost = contactByPubkey.has(a.pubkey) ? 0.5 : 0;
2412
+ return { agent: a, score: hits + contactBoost };
2409
2413
  });
2410
2414
  filtered = scored.filter((s) => s.score > 0).sort((a, b) => b.score - a.score).map((s) => s.agent);
2411
2415
  }
2416
+ } else if (contactByPubkey.size > 0) {
2417
+ filtered = [...filtered].sort((left, right) => {
2418
+ const leftContact = contactByPubkey.get(left.pubkey);
2419
+ const rightContact = contactByPubkey.get(right.pubkey);
2420
+ if (leftContact && !rightContact) {
2421
+ return -1;
2422
+ }
2423
+ if (rightContact && !leftContact) {
2424
+ return 1;
2425
+ }
2426
+ if (leftContact && rightContact) {
2427
+ const leftTs = leftContact.lastJobAt ?? leftContact.addedAt;
2428
+ const rightTs = rightContact.lastJobAt ?? rightContact.addedAt;
2429
+ return rightTs - leftTs;
2430
+ }
2431
+ return 0;
2432
+ });
2412
2433
  }
2413
2434
  if (filtered.length === 0) {
2414
2435
  return textResult(
@@ -2440,30 +2461,36 @@ var discoveryTools = [
2440
2461
  } catch {
2441
2462
  }
2442
2463
  }
2443
- const results = filtered.map((a) => ({
2444
- npub: a.npub,
2445
- name: sanitizeField(a.name || "", 200),
2446
- cards: a.cards.map((card) => {
2447
- const asset = assetFromCardPayment(card.payment);
2448
- const price = card.payment?.job_price;
2449
- const gasEstimate = price ? gasByAtaNeed.get(asset.mint !== void 0) : void 0;
2450
- return {
2451
- name: sanitizeField(card.name || "", 200),
2452
- description: sanitizeField(card.description || "", 500),
2453
- capabilities: card.capabilities,
2454
- job_price_subunits: price,
2455
- price_display: price ? formatAssetAmount(asset, BigInt(price)) : "free",
2456
- asset_token: asset.token,
2457
- asset_symbol: asset.symbol,
2458
- asset_mint: asset.mint,
2459
- chain: card.payment?.chain,
2460
- network: card.payment?.network,
2461
- network_fee_estimate_sol: gasEstimate
2462
- };
2463
- }),
2464
- supported_kinds: a.supportedKinds,
2465
- last_worked_at: contacts_only ? lastWorkedAtByPubkey.get(a.pubkey) : void 0
2466
- }));
2464
+ const results = filtered.map((a) => {
2465
+ const contact = contactByPubkey.get(a.pubkey);
2466
+ return {
2467
+ npub: a.npub,
2468
+ name: sanitizeField(a.name || "", 200),
2469
+ cards: a.cards.map((card) => {
2470
+ const asset = assetFromCardPayment(card.payment);
2471
+ const price = card.payment?.job_price;
2472
+ const gasEstimate = price ? gasByAtaNeed.get(asset.mint !== void 0) : void 0;
2473
+ return {
2474
+ name: sanitizeField(card.name || "", 200),
2475
+ description: sanitizeField(card.description || "", 500),
2476
+ capabilities: card.capabilities,
2477
+ job_price_subunits: price,
2478
+ price_display: price ? formatAssetAmount(asset, BigInt(price)) : "free",
2479
+ asset_token: asset.token,
2480
+ asset_symbol: asset.symbol,
2481
+ asset_mint: asset.mint,
2482
+ chain: card.payment?.chain,
2483
+ network: card.payment?.network,
2484
+ network_fee_estimate_sol: gasEstimate
2485
+ };
2486
+ }),
2487
+ supported_kinds: a.supportedKinds,
2488
+ is_contact: contact ? true : void 0,
2489
+ last_worked_at: contact ? contact.lastJobAt ?? contact.addedAt : void 0,
2490
+ last_capability: contact?.lastCapability,
2491
+ contact_note: contact?.note ? sanitizeField(contact.note, 500) : void 0
2492
+ };
2493
+ });
2467
2494
  const { text } = sanitizeUntrusted(JSON.stringify(results, null, 2), "structured");
2468
2495
  return textResult(text);
2469
2496
  }