@panal/sdk 0.10.0 → 0.10.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/client.d.ts CHANGED
@@ -65,6 +65,31 @@ export interface HireResult {
65
65
  /** El hash del brief que quedó registrado, para poder probarlo después. */
66
66
  taskHash: Hex;
67
67
  }
68
+ /**
69
+ * ¿Esto que manda el indexador es un nombre de PanalNames?
70
+ *
71
+ * Se valida como todo lo que llega de un servicio: si viene a medias se
72
+ * descarta, porque un `origen` inventado haria que la web avisara de una venta
73
+ * que no existio, o peor, que callara una que si.
74
+ */
75
+ /**
76
+ * La skill pedida y, detrás, versiones cada vez más generales de ella.
77
+ *
78
+ * `searchAgents` exige que TODAS las palabras aparezcan, así que cuantas más
79
+ * lleve la skill, menos gente la cumple. Quien escribe estas cadenas suele ser
80
+ * un modelo, y un modelo pide "Spanish tax law" donde el mercado vende "tax".
81
+ *
82
+ * Se recorta POR LA IZQUIERDA porque en inglés el núcleo del sintagma va al
83
+ * final: "Spanish tax law" → "tax law" → "law" sigue hablando de lo mismo.
84
+ * Recortar por la derecha dejaría "Spanish", que casa con cualquier cosa
85
+ * española y con nada de impuestos: peor que no encontrar a nadie, porque se
86
+ * pagaría al agente equivocado.
87
+ *
88
+ * Nunca baja de una palabra y nunca devuelve duplicados, así que en el caso
89
+ * normal —una o dos palabras, que es lo que el prompt pide— esto es una sola
90
+ * búsqueda y no cambia nada.
91
+ */
92
+ export declare function variantesDeSkill(skill: string): string[];
68
93
  export declare class PanalClient {
69
94
  readonly network: PanalNetwork;
70
95
  readonly addresses: PanalAddresses;
@@ -290,6 +315,7 @@ export declare class PanalClient {
290
315
  depth?: number;
291
316
  }): Promise<AskResult & {
292
317
  agent: Address;
318
+ skill: string;
293
319
  }>;
294
320
  /**
295
321
  * Dónde escucha el x402 de un agente.
package/dist/client.js CHANGED
@@ -33,6 +33,35 @@ const REGISTRY_MAX = 500;
33
33
  * descarta, porque un `origen` inventado haria que la web avisara de una venta
34
34
  * que no existio, o peor, que callara una que si.
35
35
  */
36
+ /**
37
+ * La skill pedida y, detrás, versiones cada vez más generales de ella.
38
+ *
39
+ * `searchAgents` exige que TODAS las palabras aparezcan, así que cuantas más
40
+ * lleve la skill, menos gente la cumple. Quien escribe estas cadenas suele ser
41
+ * un modelo, y un modelo pide "Spanish tax law" donde el mercado vende "tax".
42
+ *
43
+ * Se recorta POR LA IZQUIERDA porque en inglés el núcleo del sintagma va al
44
+ * final: "Spanish tax law" → "tax law" → "law" sigue hablando de lo mismo.
45
+ * Recortar por la derecha dejaría "Spanish", que casa con cualquier cosa
46
+ * española y con nada de impuestos: peor que no encontrar a nadie, porque se
47
+ * pagaría al agente equivocado.
48
+ *
49
+ * Nunca baja de una palabra y nunca devuelve duplicados, así que en el caso
50
+ * normal —una o dos palabras, que es lo que el prompt pide— esto es una sola
51
+ * búsqueda y no cambia nada.
52
+ */
53
+ export function variantesDeSkill(skill) {
54
+ const palabras = skill.trim().split(/\s+/).filter(Boolean);
55
+ if (palabras.length <= 1)
56
+ return [skill.trim()].filter(Boolean);
57
+ const out = [];
58
+ for (let i = 0; i < palabras.length; i++) {
59
+ const v = palabras.slice(i).join(' ');
60
+ if (!out.includes(v))
61
+ out.push(v);
62
+ }
63
+ return out;
64
+ }
36
65
  function esNombre(v) {
37
66
  if (v === null || typeof v !== 'object')
38
67
  return false;
@@ -643,11 +672,31 @@ export class PanalClient {
643
672
  // Se busca por SKILL, no por texto libre: encontrar a alguien porque la
644
673
  // palabra aparece en su descripción no sirve para delegar. Si el indexador
645
674
  // no está, `searchAgents` cae solo a la cadena con su texto libre.
646
- const candidates = (await this.searchAgents(skill, { skill }))
647
- .filter((a) => !excluded.has(a.address.toLowerCase()) && a.metadata.botUrl)
648
- .slice(0, options.maxCandidates ?? 5);
649
- if (!candidates.length)
650
- throw new X402Error(`Ningún agente activo con la skill "${skill}" publica endpoint.`);
675
+ //
676
+ // La búsqueda exige que TODAS las palabras casen, así que una skill de más
677
+ // de dos palabras no encuentra a nadie casi nunca: quien la escribe es un
678
+ // modelo, y un modelo pide "Spanish tax law" donde el mercado vende "tax".
679
+ // Se reintenta quitando palabras POR LA IZQUIERDA porque en inglés el
680
+ // núcleo va al final: "Spanish tax law" → "tax law" → "law". Así se
681
+ // generaliza sin perder de qué se estaba hablando; recortar por la derecha
682
+ // dejaría "Spanish", que casaría con cualquier cosa española.
683
+ let candidates = [];
684
+ let usada = skill;
685
+ for (const intento of variantesDeSkill(skill)) {
686
+ candidates = (await this.searchAgents(intento, { skill: intento }))
687
+ .filter((a) => !excluded.has(a.address.toLowerCase()) && a.metadata.botUrl)
688
+ .slice(0, options.maxCandidates ?? 5);
689
+ if (candidates.length) {
690
+ usada = intento;
691
+ break;
692
+ }
693
+ }
694
+ if (!candidates.length) {
695
+ throw new X402Error(`Ningún agente activo con la skill "${skill}" publica endpoint.` +
696
+ (variantesDeSkill(skill).length > 1
697
+ ? ` Se probó también con ${variantesDeSkill(skill).slice(1).map((v) => `"${v}"`).join(' y ')}.`
698
+ : ''));
699
+ }
651
700
  const quotes = [];
652
701
  const rechazos = [];
653
702
  for (const agent of candidates) {
@@ -683,7 +732,10 @@ export class PanalClient {
683
732
  quote: elegido.accept,
684
733
  envelope: siguiente,
685
734
  });
686
- return { ...result, agent: elegido.agent.address };
735
+ // `skill` es la que de verdad encontró al vendedor, que puede no ser la que
736
+ // pediste: quien llama necesita poder decirlo en su log, o cada búsqueda
737
+ // ensanchada es un cambio de comportamiento invisible.
738
+ return { ...result, agent: elegido.agent.address, skill: usada };
687
739
  }
688
740
  /**
689
741
  * Dónde escucha el x402 de un agente.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@panal/sdk",
3
- "version": "0.10.0",
3
+ "version": "0.10.1",
4
4
  "description": "SDK de Panal: contrata agentes de IA autonomos on-chain en Monad",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -45,7 +45,7 @@
45
45
  "scripts": {
46
46
  "build": "tsc -p tsconfig.json",
47
47
  "typecheck": "tsc -p tsconfig.json --noEmit",
48
- "test": "tsx test/sdk.test.ts && tsx test/x402.test.ts && tsx test/x402-server.test.ts && tsx test/envelope.test.ts && tsx test/files.test.ts",
48
+ "test": "tsx test/sdk.test.ts && tsx test/x402.test.ts && tsx test/x402-server.test.ts && tsx test/envelope.test.ts && tsx test/files.test.ts && tsx test/skill.test.ts",
49
49
  "test:nombres": "tsx test/nombres.test.ts"
50
50
  }
51
51
  }