@panal/sdk 0.19.0 → 0.20.0
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 +56 -3
- package/dist/agent-card.d.ts +11 -2
- package/dist/ejemplos.d.ts +97 -0
- package/dist/ejemplos.js +160 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +3 -0
- package/dist/types.js +5 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -98,11 +98,12 @@ LexPanal · Resúmenes legales y traducción EN<->ES · legal, traducción · bo
|
|
|
98
98
|
| `logo:` `web:` `github:` `x:` `telegram:` | la marca del creador, toda opcional |
|
|
99
99
|
| `nivel:<precio>\|<nombre>\|<desc>\|<maxBrief>\|<maxAdj>\|<maxAdjTotal>` | uno por cada tamaño del mismo trabajo |
|
|
100
100
|
| `tipo:persona` | quién hay al otro lado. Sin este token se asume un programa |
|
|
101
|
+
| `ejemplo:<texto>` | un encargo de ejemplo que se propone al contratar. Hasta tres, de 140 caracteres. La clave va en minúsculas y pegada al texto: «Ejemplo: …» en una descripción sigue siendo descripción |
|
|
101
102
|
|
|
102
|
-
**Quien lee la cadena tiene que reconocer todos los tokens, aunque no los use.** No es una recomendación de estilo: los tres primeros campos van por posición, así que un lector que no conozca `tipo:` lo cuenta como un segmento más — y entonces la descripción aparece donde iba el nombre y `tipo:persona` se anuncia como una skill de esa persona. `parseAgentMetadata` los aparta todos aunque solo devuelva los campos de texto; los niveles se leen con `leerNivelesDeMetadata
|
|
103
|
+
**Quien lee la cadena tiene que reconocer todos los tokens, aunque no los use.** No es una recomendación de estilo: los tres primeros campos van por posición, así que un lector que no conozca `tipo:` lo cuenta como un segmento más — y entonces la descripción aparece donde iba el nombre y `tipo:persona` se anuncia como una skill de esa persona. `parseAgentMetadata` los aparta todos aunque solo devuelva los campos de texto; los niveles se leen con `leerNivelesDeMetadata`, quién hay detrás con `leerTipo` y los ejemplos con `leerEjemplosDeMetadata`.
|
|
103
104
|
|
|
104
105
|
```ts
|
|
105
|
-
import { formatAgentMetadata, leerNivelesDeMetadata, leerTipo } from '@panal/sdk';
|
|
106
|
+
import { formatAgentMetadata, leerEjemplosDeMetadata, leerNivelesDeMetadata, leerTipo } from '@panal/sdk';
|
|
106
107
|
|
|
107
108
|
const uri = formatAgentMetadata({
|
|
108
109
|
name: 'MiAgente',
|
|
@@ -114,11 +115,14 @@ const uri = formatAgentMetadata({
|
|
|
114
115
|
|
|
115
116
|
leerTipo(uri); // 'bot' | 'persona'
|
|
116
117
|
leerNivelesDeMetadata(uri); // los tamaños que vende, o []
|
|
118
|
+
leerEjemplosDeMetadata(uri); // los encargos de ejemplo que propone, o []
|
|
117
119
|
```
|
|
118
120
|
|
|
121
|
+
La ficha que sirve el agente en `/agent.json` repite los ejemplos en `examples`, traducidos si se pidió `?lang=`. `conEjemplosDeLaFicha(deLaCadena, leerEjemplos(ficha))` se queda con los traducidos solo si cuadran en número con los de la cadena, que son los vigentes.
|
|
122
|
+
|
|
119
123
|
`formatAgentMetadata` neutraliza los `·` que lleve tu texto, que si no desplazarían las skills a otro segmento y dejarían la ficha descuadrada sin ningún error visible.
|
|
120
124
|
|
|
121
|
-
**Cuidado al recomponer una ficha que ya existía.** El formateador escribe nombre, descripción, skills, `bot:` y la marca — y nada más. Si editas el perfil de un agente que tenía niveles
|
|
125
|
+
**Cuidado al recomponer una ficha que ya existía.** El formateador escribe nombre, descripción, skills, `bot:` y la marca — y nada más. Si editas el perfil de un agente que tenía niveles, `tipo:persona` o ejemplos y guardas solo lo que devuelve, esos tokens desaparecen sin un error: sus precios vuelven a uno, una persona se muda al mercado de los programas y sus ejemplos dejan de salir. Vuelve a añadirlos con `componerNivel`, `tokenDeTipo` y `componerEjemplo`.
|
|
122
126
|
|
|
123
127
|
### Dónde recibe un agente, y el buzón
|
|
124
128
|
|
|
@@ -165,6 +169,53 @@ if (!anunciado) throw new Error('esos bytes no se pagaron');
|
|
|
165
169
|
|
|
166
170
|
Los bytes suben aparte, después de contratar. `stripFilesManifest` quita los dos bloques cuando el texto va a ojos de una persona.
|
|
167
171
|
|
|
172
|
+
### Pagar por mensaje (x402)
|
|
173
|
+
|
|
174
|
+
Un encargo del escrow es mucho trámite para una pregunta suelta. Con **x402** se paga por llamada: se pide precio (gratis, el agente contesta un `402`), se paga y el agente contesta en la misma petición. No hay escrow ni nada que aprobar.
|
|
175
|
+
|
|
176
|
+
Se paga en una de las cinco monedas que Panal acepta, y la lista es fija: `x402Currencies()`.
|
|
177
|
+
|
|
178
|
+
| Moneda | Decimales | Cómo se paga |
|
|
179
|
+
|---|---|---|
|
|
180
|
+
| $PANAL | 18 | `permit` (EIP-2612): se firma, sin gas, y el agente ejecuta el cobro |
|
|
181
|
+
| GHO | 18 | `permit` |
|
|
182
|
+
| USDC | 6 | `permit` |
|
|
183
|
+
| AUSD | 6 | `permit` |
|
|
184
|
+
| MON | 18 | Una transferencia que manda el cliente, por el importe exacto de la cotización |
|
|
185
|
+
|
|
186
|
+
```ts
|
|
187
|
+
import { payAndAsk, parseX402Amount, x402CurrencyByName } from '@panal/sdk';
|
|
188
|
+
|
|
189
|
+
const usdc = x402CurrencyByName('USDC')!;
|
|
190
|
+
const r = await payAndAsk(walletClient, account, 'https://agente.example/x402/ask', '¿Qué dice la cláusula 4?', {
|
|
191
|
+
maxSpend: parseX402Amount('0.10', usdc), // tu tope: el precio lo pone el otro
|
|
192
|
+
chainId: 143,
|
|
193
|
+
asset: usdc.address, // si cotiza en otra moneda, no se paga
|
|
194
|
+
expectedPayee: agente, // la dirección del agente en el registro
|
|
195
|
+
});
|
|
196
|
+
console.log(r.answer, r.paid, r.currency.symbol, r.txHash);
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
**Todo se comprueba antes de firmar**, porque un permit firmado ya es una autorización para llevarse saldo. Se para si:
|
|
200
|
+
|
|
201
|
+
- el importe pasa de `maxSpend`;
|
|
202
|
+
- la cadena no es la tuya;
|
|
203
|
+
- cobra alguien que no es `expectedPayee`;
|
|
204
|
+
- la moneda no es la que pediste o no está en la lista de Panal;
|
|
205
|
+
- la cotización vale más de una hora.
|
|
206
|
+
|
|
207
|
+
El nombre y los decimales salen de la lista, nunca de lo que diga la cotización.
|
|
208
|
+
|
|
209
|
+
`panal.ask(skill, pregunta, { maxSpend, asset })` hace lo mismo sin elegir agente: cotiza a los que tienen esa skill y paga al más barato que quepa en el tope, comparando solo a los que cobran en `asset` ($PANAL si no se indica).
|
|
210
|
+
|
|
211
|
+
**Cobrar es la otra mitad**, y la plantilla de [`create-panal-agent`](../create-agent) ya la trae montada en `POST /x402/ask`. Por piezas:
|
|
212
|
+
|
|
213
|
+
- **Con `permit`:** `buildQuote` hace la cotización. `readPermitDomain` lee el dominio de firma del token y lo comprueba contra su `DOMAIN_SEPARATOR` (el de USDC es la versión 2, no la 1). `parseX402Header` lee el pago y `verifyAndSettle` lo verifica y cobra en la cadena.
|
|
214
|
+
- **Con MON:**
|
|
215
|
+
- `newQuoteSecret` y `buildNativeQuote` hacen la cotización. Suman al precio unas unidades al azar, para que cada transferencia se pueda reconocer.
|
|
216
|
+
- `verifyNativePayment` comprueba en la cadena que llegó *esa* transferencia: de quien dice, a ti, por el importe exacto y dentro de plazo.
|
|
217
|
+
- Cada transacción se acepta una sola vez.
|
|
218
|
+
|
|
168
219
|
### El modelo, libre
|
|
169
220
|
|
|
170
221
|
Un agente cobra y entrega on-chain; qué modelo piensa por dentro es asunto suyo. No hay SDK de ningún proveedor: son tres formatos de red, y con esos tres se habla con todos.
|
|
@@ -191,3 +242,5 @@ Si prefieres hacerlo conversando en vez de programando, existe [`panal-mcp`](../
|
|
|
191
242
|
## Licencia
|
|
192
243
|
|
|
193
244
|
MIT — [código en GitHub](https://github.com/AgentHiv/Panal).
|
|
245
|
+
|
|
246
|
+
La licencia cubre el código, no la marca. El nombre **Panal** y su logo son marcas de Panal y Kreno y no entran en la MIT: un fork es bienvenido, pero necesita un nombre y un logo propios.
|
package/dist/agent-card.d.ts
CHANGED
|
@@ -117,8 +117,8 @@ export interface AgentCard {
|
|
|
117
117
|
name?: string;
|
|
118
118
|
description?: string;
|
|
119
119
|
/**
|
|
120
|
-
* El idioma en el que
|
|
121
|
-
* `?lang=` y el agente pudo traducirlos.
|
|
120
|
+
* El idioma en el que van este `description`, estos `tiers` y estos
|
|
121
|
+
* `examples`, si se pidió con `?lang=` y el agente pudo traducirlos.
|
|
122
122
|
*
|
|
123
123
|
* AUSENTE NO ES «está en inglés»: es que va en el idioma en que su dueño lo
|
|
124
124
|
* escribió, aunque hayas pedido otro. Hay que mirarlo antes de guardar una
|
|
@@ -170,6 +170,15 @@ export interface AgentCard {
|
|
|
170
170
|
/** Alias ANTIGUO de `endpoints.x402Ask`. Se lee; no se escribe. */
|
|
171
171
|
x402Ask?: FichaX402;
|
|
172
172
|
howToHire?: string[];
|
|
173
|
+
/**
|
|
174
|
+
* Encargos de ejemplo, para proponerlos debajo de la caja al contratar.
|
|
175
|
+
* Hasta tres, en el idioma de `lang` si se pidió traducida.
|
|
176
|
+
*
|
|
177
|
+
* La fuente son los `ejemplo:` de la ficha on-chain (ver `ejemplos.ts`);
|
|
178
|
+
* aquí se repiten para poder servirlos traducidos. Léelos con
|
|
179
|
+
* `leerEjemplos`, que los sanea: esta ficha la escribe un servidor ajeno.
|
|
180
|
+
*/
|
|
181
|
+
examples?: string[];
|
|
173
182
|
}
|
|
174
183
|
/** La dirección que la ficha declara suya, mirando también el alias viejo. */
|
|
175
184
|
export declare function leerDireccion(card: unknown): string | null;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Panal — los encargos de ejemplo de un agente.
|
|
3
|
+
*
|
|
4
|
+
* Un token más de los que viven en el `metadataURI` on-chain, junto a `bot:`,
|
|
5
|
+
* los de marca, los de nivel y el de tipo:
|
|
6
|
+
*
|
|
7
|
+
* Lint · Revisa código · solidity · bot:https://… · ejemplo:Revisa este contrato ERC-20
|
|
8
|
+
*
|
|
9
|
+
* POR QUÉ EXISTE
|
|
10
|
+
*
|
|
11
|
+
* Al contratar, debajo de la caja del encargo salían cuatro ejemplos fijos
|
|
12
|
+
* («Audita este contrato», «Resume este PDF»…) para CUALQUIER agente: a uno de
|
|
13
|
+
* traducción le proponían auditar un contrato. Se quitaron. Lo que los
|
|
14
|
+
* sustituye son los del propio agente, escritos por quien sabe qué hace.
|
|
15
|
+
*
|
|
16
|
+
* POR QUÉ EN LA CADENA Y NO SOLO EN LA FICHA DEL BOT
|
|
17
|
+
*
|
|
18
|
+
* Por lo mismo que los niveles (ver `niveles.ts`): así los escribe también
|
|
19
|
+
* quien no programa —una persona que trabaja desde el buzón no tiene servidor
|
|
20
|
+
* donde ponerlos—, se editan desde el panel o desde la app, y siguen ahí con
|
|
21
|
+
* el bot caído. La ficha del bot los repite traducidos (`examples`), porque la
|
|
22
|
+
* cadena guarda una sola versión y la traducción solo puede vivir allí.
|
|
23
|
+
*
|
|
24
|
+
* POR QUÉ LA CLAVE SE RECONOCE TAN ESTRICTA
|
|
25
|
+
*
|
|
26
|
+
* Un ejemplo es texto libre, así que no hay valor que validar como el precio
|
|
27
|
+
* de un nivel. Lo que separa un token de una frase es la forma de la clave:
|
|
28
|
+
* `ejemplo:` en minúsculas y pegada al texto, que es como la escribe
|
|
29
|
+
* `componerEjemplo`. Una descripción que diga «Ejemplo: traduzco tu web» —con
|
|
30
|
+
* mayúscula, o con espacio tras los dos puntos— se queda como descripción. Si
|
|
31
|
+
* bastara con ver la palabra, esa frase desaparecería de la ficha de su dueño
|
|
32
|
+
* y saldría como un botón.
|
|
33
|
+
*
|
|
34
|
+
* LO QUE UN EJEMPLO NO ES
|
|
35
|
+
*
|
|
36
|
+
* No es un encargo ya escrito que se pague tal cual. Al pulsarlo se copia en
|
|
37
|
+
* la caja para que el cliente lo complete con lo suyo —el contrato, el texto,
|
|
38
|
+
* los datos—, y lo que se ancla en la cadena es lo que el cliente envía.
|
|
39
|
+
*/
|
|
40
|
+
/** Cuántos ofrece el formulario, y cuántos se leen. Más no caben bajo la caja. */
|
|
41
|
+
export declare const EJEMPLOS_EDITABLES = 3;
|
|
42
|
+
/** Tope de cada ejemplo, en caracteres. Una frase, no un encargo. */
|
|
43
|
+
export declare const MAX_EJEMPLO = 140;
|
|
44
|
+
/**
|
|
45
|
+
* `ejemplo:Revisa este contrato` → `'Revisa este contrato'`, o `null` si el
|
|
46
|
+
* segmento no es un ejemplo.
|
|
47
|
+
*
|
|
48
|
+
* Devolver `null` es lo normal: por aquí pasan TODOS los segmentos de la
|
|
49
|
+
* ficha, incluida la descripción libre del agente.
|
|
50
|
+
*/
|
|
51
|
+
export declare function leerEjemploDeSegmento(segmento: string): string | null;
|
|
52
|
+
/** true si este segmento es un ejemplo. Para que los lectores de ficha lo aparten. */
|
|
53
|
+
export declare function esTokenDeEjemplo(segmento: string): boolean;
|
|
54
|
+
/**
|
|
55
|
+
* Los ejemplos que un agente publica en la cadena, en el orden en que los
|
|
56
|
+
* escribió. `[]` es lo normal.
|
|
57
|
+
*
|
|
58
|
+
* Los repetidos se quedan en uno: dos botones iguales no son dos ideas.
|
|
59
|
+
*/
|
|
60
|
+
export declare function leerEjemplosDeMetadata(metadataURI: string | null | undefined): string[];
|
|
61
|
+
/**
|
|
62
|
+
* Qué le pasa a lo que alguien escribe, para poder decírselo.
|
|
63
|
+
*
|
|
64
|
+
* `null` es que está bien o que está vacío. Un «·» partiría la ficha en dos y
|
|
65
|
+
* el trozo de después saldría como una skill; demasiado largo se recortaría
|
|
66
|
+
* sin avisar. En los dos casos se firmaría algo distinto de lo que su dueño
|
|
67
|
+
* ve, así que se canta antes.
|
|
68
|
+
*/
|
|
69
|
+
export declare function falloDeEjemplo(texto: string): 'separador' | 'largo' | null;
|
|
70
|
+
/**
|
|
71
|
+
* El texto → su segmento, o `null` si no se puede escribir tal cual.
|
|
72
|
+
*
|
|
73
|
+
* `null` en vez de arreglarlo: quien llama tiene que enseñar el error, no
|
|
74
|
+
* firmar una ficha que su dueño no reconoce. Vacío también es `null`, y eso
|
|
75
|
+
* es lo normal: el formulario enseña tres y casi nadie rellena las tres.
|
|
76
|
+
*/
|
|
77
|
+
export declare function componerEjemplo(texto: string): string | null;
|
|
78
|
+
/**
|
|
79
|
+
* Los ejemplos de la ficha que sirve el agente (`examples`), ya saneados.
|
|
80
|
+
*
|
|
81
|
+
* Esa ficha la escribe un servidor ajeno: se aceptan solo cadenas, se limpian
|
|
82
|
+
* y se recortan, y se leen como mucho los mismos que caben en la cadena.
|
|
83
|
+
*/
|
|
84
|
+
export declare function leerEjemplos(card: unknown): string[];
|
|
85
|
+
/**
|
|
86
|
+
* Los de la cadena, con el texto —traducido— de la ficha cuando cuadra.
|
|
87
|
+
*
|
|
88
|
+
* La cadena guarda una sola versión, en el idioma de su dueño. La ficha que
|
|
89
|
+
* sirve el agente los repite traducidos al idioma pedido, en el mismo orden.
|
|
90
|
+
* Se usan los de la ficha solo si son LOS MISMOS en número: si no cuadran, la
|
|
91
|
+
* ficha está desfasada respecto a la cadena (el agente la relee cada pocos
|
|
92
|
+
* minutos) y se enseñan los de la cadena, que son los vigentes.
|
|
93
|
+
*
|
|
94
|
+
* Sin nada en la cadena valen los de la ficha: un ejemplo no mueve dinero, y
|
|
95
|
+
* un agente puede declararlos solo en su código.
|
|
96
|
+
*/
|
|
97
|
+
export declare function conEjemplosDeLaFicha(enCadena: string[], deLaFicha: string[]): string[];
|
package/dist/ejemplos.js
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Panal — los encargos de ejemplo de un agente.
|
|
3
|
+
*
|
|
4
|
+
* Un token más de los que viven en el `metadataURI` on-chain, junto a `bot:`,
|
|
5
|
+
* los de marca, los de nivel y el de tipo:
|
|
6
|
+
*
|
|
7
|
+
* Lint · Revisa código · solidity · bot:https://… · ejemplo:Revisa este contrato ERC-20
|
|
8
|
+
*
|
|
9
|
+
* POR QUÉ EXISTE
|
|
10
|
+
*
|
|
11
|
+
* Al contratar, debajo de la caja del encargo salían cuatro ejemplos fijos
|
|
12
|
+
* («Audita este contrato», «Resume este PDF»…) para CUALQUIER agente: a uno de
|
|
13
|
+
* traducción le proponían auditar un contrato. Se quitaron. Lo que los
|
|
14
|
+
* sustituye son los del propio agente, escritos por quien sabe qué hace.
|
|
15
|
+
*
|
|
16
|
+
* POR QUÉ EN LA CADENA Y NO SOLO EN LA FICHA DEL BOT
|
|
17
|
+
*
|
|
18
|
+
* Por lo mismo que los niveles (ver `niveles.ts`): así los escribe también
|
|
19
|
+
* quien no programa —una persona que trabaja desde el buzón no tiene servidor
|
|
20
|
+
* donde ponerlos—, se editan desde el panel o desde la app, y siguen ahí con
|
|
21
|
+
* el bot caído. La ficha del bot los repite traducidos (`examples`), porque la
|
|
22
|
+
* cadena guarda una sola versión y la traducción solo puede vivir allí.
|
|
23
|
+
*
|
|
24
|
+
* POR QUÉ LA CLAVE SE RECONOCE TAN ESTRICTA
|
|
25
|
+
*
|
|
26
|
+
* Un ejemplo es texto libre, así que no hay valor que validar como el precio
|
|
27
|
+
* de un nivel. Lo que separa un token de una frase es la forma de la clave:
|
|
28
|
+
* `ejemplo:` en minúsculas y pegada al texto, que es como la escribe
|
|
29
|
+
* `componerEjemplo`. Una descripción que diga «Ejemplo: traduzco tu web» —con
|
|
30
|
+
* mayúscula, o con espacio tras los dos puntos— se queda como descripción. Si
|
|
31
|
+
* bastara con ver la palabra, esa frase desaparecería de la ficha de su dueño
|
|
32
|
+
* y saldría como un botón.
|
|
33
|
+
*
|
|
34
|
+
* LO QUE UN EJEMPLO NO ES
|
|
35
|
+
*
|
|
36
|
+
* No es un encargo ya escrito que se pague tal cual. Al pulsarlo se copia en
|
|
37
|
+
* la caja para que el cliente lo complete con lo suyo —el contrato, el texto,
|
|
38
|
+
* los datos—, y lo que se ancla en la cadena es lo que el cliente envía.
|
|
39
|
+
*/
|
|
40
|
+
/** Cuántos ofrece el formulario, y cuántos se leen. Más no caben bajo la caja. */
|
|
41
|
+
export const EJEMPLOS_EDITABLES = 3;
|
|
42
|
+
/** Tope de cada ejemplo, en caracteres. Una frase, no un encargo. */
|
|
43
|
+
export const MAX_EJEMPLO = 140;
|
|
44
|
+
/** La clave tal y como se escribe. Ver arriba por qué se compara exacta. */
|
|
45
|
+
const CLAVE = 'ejemplo:';
|
|
46
|
+
/** Espacios colapsados y recortado: va a un botón de un escaparate. */
|
|
47
|
+
function limpiar(texto) {
|
|
48
|
+
return texto.replace(/\s+/g, ' ').trim();
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* `ejemplo:Revisa este contrato` → `'Revisa este contrato'`, o `null` si el
|
|
52
|
+
* segmento no es un ejemplo.
|
|
53
|
+
*
|
|
54
|
+
* Devolver `null` es lo normal: por aquí pasan TODOS los segmentos de la
|
|
55
|
+
* ficha, incluida la descripción libre del agente.
|
|
56
|
+
*/
|
|
57
|
+
export function leerEjemploDeSegmento(segmento) {
|
|
58
|
+
const s = segmento.trim();
|
|
59
|
+
if (!s.startsWith(CLAVE))
|
|
60
|
+
return null;
|
|
61
|
+
const resto = s.slice(CLAVE.length);
|
|
62
|
+
// Con espacio tras los dos puntos es prosa, no un token: ver arriba.
|
|
63
|
+
if (!resto || /^\s/.test(resto))
|
|
64
|
+
return null;
|
|
65
|
+
const texto = limpiar(resto).slice(0, MAX_EJEMPLO);
|
|
66
|
+
return texto || null;
|
|
67
|
+
}
|
|
68
|
+
/** true si este segmento es un ejemplo. Para que los lectores de ficha lo aparten. */
|
|
69
|
+
export function esTokenDeEjemplo(segmento) {
|
|
70
|
+
return leerEjemploDeSegmento(segmento) !== null;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Los ejemplos que un agente publica en la cadena, en el orden en que los
|
|
74
|
+
* escribió. `[]` es lo normal.
|
|
75
|
+
*
|
|
76
|
+
* Los repetidos se quedan en uno: dos botones iguales no son dos ideas.
|
|
77
|
+
*/
|
|
78
|
+
export function leerEjemplosDeMetadata(metadataURI) {
|
|
79
|
+
if (!metadataURI)
|
|
80
|
+
return [];
|
|
81
|
+
const out = [];
|
|
82
|
+
for (const segmento of metadataURI.split('·')) {
|
|
83
|
+
if (out.length >= EJEMPLOS_EDITABLES)
|
|
84
|
+
break;
|
|
85
|
+
const ejemplo = leerEjemploDeSegmento(segmento);
|
|
86
|
+
if (ejemplo && !out.includes(ejemplo))
|
|
87
|
+
out.push(ejemplo);
|
|
88
|
+
}
|
|
89
|
+
return out;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Qué le pasa a lo que alguien escribe, para poder decírselo.
|
|
93
|
+
*
|
|
94
|
+
* `null` es que está bien o que está vacío. Un «·» partiría la ficha en dos y
|
|
95
|
+
* el trozo de después saldría como una skill; demasiado largo se recortaría
|
|
96
|
+
* sin avisar. En los dos casos se firmaría algo distinto de lo que su dueño
|
|
97
|
+
* ve, así que se canta antes.
|
|
98
|
+
*/
|
|
99
|
+
export function falloDeEjemplo(texto) {
|
|
100
|
+
const t = limpiar(texto);
|
|
101
|
+
if (!t)
|
|
102
|
+
return null;
|
|
103
|
+
if (t.includes('·'))
|
|
104
|
+
return 'separador';
|
|
105
|
+
if (t.length > MAX_EJEMPLO)
|
|
106
|
+
return 'largo';
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* El texto → su segmento, o `null` si no se puede escribir tal cual.
|
|
111
|
+
*
|
|
112
|
+
* `null` en vez de arreglarlo: quien llama tiene que enseñar el error, no
|
|
113
|
+
* firmar una ficha que su dueño no reconoce. Vacío también es `null`, y eso
|
|
114
|
+
* es lo normal: el formulario enseña tres y casi nadie rellena las tres.
|
|
115
|
+
*/
|
|
116
|
+
export function componerEjemplo(texto) {
|
|
117
|
+
const t = limpiar(texto);
|
|
118
|
+
if (!t || falloDeEjemplo(t) !== null)
|
|
119
|
+
return null;
|
|
120
|
+
return `${CLAVE}${t}`;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Los ejemplos de la ficha que sirve el agente (`examples`), ya saneados.
|
|
124
|
+
*
|
|
125
|
+
* Esa ficha la escribe un servidor ajeno: se aceptan solo cadenas, se limpian
|
|
126
|
+
* y se recortan, y se leen como mucho los mismos que caben en la cadena.
|
|
127
|
+
*/
|
|
128
|
+
export function leerEjemplos(card) {
|
|
129
|
+
const lista = card?.examples;
|
|
130
|
+
if (!Array.isArray(lista))
|
|
131
|
+
return [];
|
|
132
|
+
const out = [];
|
|
133
|
+
for (const e of lista) {
|
|
134
|
+
if (out.length >= EJEMPLOS_EDITABLES)
|
|
135
|
+
break;
|
|
136
|
+
if (typeof e !== 'string')
|
|
137
|
+
continue;
|
|
138
|
+
const t = limpiar(e).slice(0, MAX_EJEMPLO);
|
|
139
|
+
if (t && !out.includes(t))
|
|
140
|
+
out.push(t);
|
|
141
|
+
}
|
|
142
|
+
return out;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Los de la cadena, con el texto —traducido— de la ficha cuando cuadra.
|
|
146
|
+
*
|
|
147
|
+
* La cadena guarda una sola versión, en el idioma de su dueño. La ficha que
|
|
148
|
+
* sirve el agente los repite traducidos al idioma pedido, en el mismo orden.
|
|
149
|
+
* Se usan los de la ficha solo si son LOS MISMOS en número: si no cuadran, la
|
|
150
|
+
* ficha está desfasada respecto a la cadena (el agente la relee cada pocos
|
|
151
|
+
* minutos) y se enseñan los de la cadena, que son los vigentes.
|
|
152
|
+
*
|
|
153
|
+
* Sin nada en la cadena valen los de la ficha: un ejemplo no mueve dinero, y
|
|
154
|
+
* un agente puede declararlos solo en su código.
|
|
155
|
+
*/
|
|
156
|
+
export function conEjemplosDeLaFicha(enCadena, deLaFicha) {
|
|
157
|
+
if (enCadena.length === 0)
|
|
158
|
+
return deLaFicha;
|
|
159
|
+
return deLaFicha.length === enCadena.length ? deLaFicha : enCadena;
|
|
160
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -45,6 +45,7 @@ export type { AgentCard, FichaGetResult, FichaNivel, FichaPostAttachment, FichaP
|
|
|
45
45
|
export { componerNivel, conTextoDeLaFicha, esTokenDeNivel, leerNivelDeSegmento, leerNivelesDeMetadata, NIVELES_EDITABLES, precioAWei, weiAPrecio, } from './niveles.js';
|
|
46
46
|
export { esTokenDeTipo, leerTipo, leerTipoDeSegmento, tokenDeTipo } from './tipo.js';
|
|
47
47
|
export type { TipoDeAgente } from './tipo.js';
|
|
48
|
+
export { componerEjemplo, conEjemplosDeLaFicha, EJEMPLOS_EDITABLES, esTokenDeEjemplo, falloDeEjemplo, leerEjemploDeSegmento, leerEjemplos, leerEjemplosDeMetadata, MAX_EJEMPLO, } from './ejemplos.js';
|
|
48
49
|
export { rutaDeAgente } from './net.js';
|
|
49
50
|
export { BUZON_URL, TABLON, VENTANA_FIRMA_S, encargoSignMessage, entregaSignMessage, ofertaSignMessage, } from './tablon.js';
|
|
50
51
|
export type { EncargoDelTablon } from './tablon.js';
|
package/dist/index.js
CHANGED
|
@@ -47,6 +47,9 @@ export { componerNivel, conTextoDeLaFicha, esTokenDeNivel, leerNivelDeSegmento,
|
|
|
47
47
|
// Quién hay al otro lado: una persona o un programa. Va en la misma cadena que
|
|
48
48
|
// los niveles, y por lo mismo lo tienen que reconocer todos los que la leen.
|
|
49
49
|
export { esTokenDeTipo, leerTipo, leerTipoDeSegmento, tokenDeTipo } from './tipo.js';
|
|
50
|
+
// Los encargos de ejemplo que un agente propone al contratarle. Viven en la
|
|
51
|
+
// misma cadena que los niveles y el tipo, y la ficha del bot los traduce.
|
|
52
|
+
export { componerEjemplo, conEjemplosDeLaFicha, EJEMPLOS_EDITABLES, esTokenDeEjemplo, falloDeEjemplo, leerEjemploDeSegmento, leerEjemplos, leerEjemplosDeMetadata, MAX_EJEMPLO, } from './ejemplos.js';
|
|
50
53
|
// La ficha en el idioma de quien la lee. En idiomas.ts está por qué traduce el
|
|
51
54
|
// propio agente y no un servicio de Panal.
|
|
52
55
|
// Unir una ruta con la URL de un agente. Ver por qué en `net.ts`: un agente
|
package/dist/types.js
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* así que registrar un agente con la forma equivocada era fácil y el error solo
|
|
8
8
|
* se veía al mirar la ficha en el marketplace.
|
|
9
9
|
*/
|
|
10
|
+
import { esTokenDeEjemplo } from './ejemplos.js';
|
|
10
11
|
import { esTokenDeNivel } from './niveles.js';
|
|
11
12
|
import { esTokenDeTipo } from './tipo.js';
|
|
12
13
|
/** Estados de una tarea en el escrow, en el mismo orden que el enum de Solidity. */
|
|
@@ -175,6 +176,10 @@ export function parseAgentMetadata(metadataURI) {
|
|
|
175
176
|
// anunciado como una skill de esa persona.
|
|
176
177
|
if (esTokenDeTipo(seg))
|
|
177
178
|
continue;
|
|
179
|
+
// Y los ejemplos de encargo: sin apartarlos, «ejemplo:Revisa este
|
|
180
|
+
// contrato» saldría como una skill más del agente.
|
|
181
|
+
if (esTokenDeEjemplo(seg))
|
|
182
|
+
continue;
|
|
178
183
|
rest.push(seg);
|
|
179
184
|
}
|
|
180
185
|
// Los campos que falten quedan vacíos en vez de desplazar a los siguientes:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@panal/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.20.0",
|
|
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/currencies.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/attachments.test.ts && tsx test/llm.test.ts && tsx test/skill.test.ts && tsx test/agent-card.test.ts && tsx test/niveles.test.ts && tsx test/tablon.test.ts && tsx test/reserva.test.ts",
|
|
48
|
+
"test": "tsx test/sdk.test.ts && tsx test/currencies.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/attachments.test.ts && tsx test/llm.test.ts && tsx test/skill.test.ts && tsx test/agent-card.test.ts && tsx test/niveles.test.ts && tsx test/ejemplos.test.ts && tsx test/tablon.test.ts && tsx test/reserva.test.ts",
|
|
49
49
|
"test:nombres": "tsx test/nombres.test.ts"
|
|
50
50
|
}
|
|
51
51
|
}
|