@panal/sdk 0.16.0 → 0.17.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/dist/agent-card.d.ts +30 -0
- package/dist/client.js +4 -4
- package/dist/index.d.ts +5 -2
- package/dist/index.js +7 -1
- package/dist/net.d.ts +15 -0
- package/dist/net.js +17 -0
- package/dist/niveles.d.ts +31 -0
- package/dist/niveles.js +46 -0
- package/dist/tipo.d.ts +58 -0
- package/dist/tipo.js +77 -0
- package/dist/types.js +5 -0
- package/package.json +1 -1
package/dist/agent-card.d.ts
CHANGED
|
@@ -98,6 +98,14 @@ export interface FichaNivel {
|
|
|
98
98
|
/** Y el de todos los adjuntos juntos. */
|
|
99
99
|
maxAttachCharsTotal?: number;
|
|
100
100
|
}
|
|
101
|
+
/** Dónde deja el cliente los bytes de lo que su encargo anuncia. */
|
|
102
|
+
export interface FichaPostAttachment {
|
|
103
|
+
method?: 'POST';
|
|
104
|
+
/** Ruta relativa, con `:taskId` dentro. */
|
|
105
|
+
path?: string;
|
|
106
|
+
/** Tope por archivo, en bytes. */
|
|
107
|
+
maxAttachmentBytes?: number;
|
|
108
|
+
}
|
|
101
109
|
export interface AgentCard {
|
|
102
110
|
/** La dirección on-chain que este dominio declara suya. Es lo que verifica. */
|
|
103
111
|
agent?: Address;
|
|
@@ -108,6 +116,18 @@ export interface AgentCard {
|
|
|
108
116
|
chainId?: number;
|
|
109
117
|
name?: string;
|
|
110
118
|
description?: string;
|
|
119
|
+
/**
|
|
120
|
+
* El idioma en el que va este `description` y estos `tiers`, si se pidió con
|
|
121
|
+
* `?lang=` y el agente pudo traducirlos.
|
|
122
|
+
*
|
|
123
|
+
* AUSENTE NO ES «está en inglés»: es que va en el idioma en que su dueño lo
|
|
124
|
+
* escribió, aunque hayas pedido otro. Hay que mirarlo antes de guardar una
|
|
125
|
+
* ficha como si fuera una traducción, porque la traducción se encarga por
|
|
126
|
+
* detrás: pedirla antes de que esté lista devuelve la ficha original con un
|
|
127
|
+
* 200 impecable. Un indexador que no lo mirara guardaría el texto original
|
|
128
|
+
* como las diez traducciones y no volvería a por ellas nunca.
|
|
129
|
+
*/
|
|
130
|
+
lang?: string;
|
|
111
131
|
skills?: string[];
|
|
112
132
|
price?: {
|
|
113
133
|
amountWei?: string;
|
|
@@ -135,6 +155,16 @@ export interface AgentCard {
|
|
|
135
155
|
postBrief?: FichaPostBrief;
|
|
136
156
|
getResult?: FichaGetResult;
|
|
137
157
|
x402Ask?: FichaX402;
|
|
158
|
+
/**
|
|
159
|
+
* Dónde subir los archivos que el encargo anuncia, si los acepta.
|
|
160
|
+
*
|
|
161
|
+
* AUSENTE ES «no los acepta». Importa porque el manifiesto de adjuntos
|
|
162
|
+
* viaja DENTRO del brief —dentro de lo que se hashea al pagar—, así que un
|
|
163
|
+
* agente sin esta ruta acepta el encargo, trabaja sin los archivos,
|
|
164
|
+
* entrega y cobra sin que nada dé error. Por eso el cliente pregunta antes
|
|
165
|
+
* de ofrecer el clip; ver `leerCapacidades` en la web.
|
|
166
|
+
*/
|
|
167
|
+
postAttachment?: FichaPostAttachment;
|
|
138
168
|
indexer?: string | null;
|
|
139
169
|
};
|
|
140
170
|
/** Alias ANTIGUO de `endpoints.x402Ask`. Se lee; no se escribe. */
|
package/dist/client.js
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
import { createPublicClient, createWalletClient, formatEther, getAddress, http, keccak256, toBytes } from 'viem';
|
|
19
19
|
import { erc20Abi, escrowAbi, namesAbi, registryAbi } from './abis.js';
|
|
20
20
|
import { leerX402 } from './agent-card.js';
|
|
21
|
-
import { assertPublicUrl, fetchLimited } from './net.js';
|
|
21
|
+
import { assertPublicUrl, fetchLimited, rutaDeAgente } from './net.js';
|
|
22
22
|
import { X402Error, payAndAsk, quoteAsk } from './x402.js';
|
|
23
23
|
import { descend, newEnvelope, remainingBudget } from './envelope.js';
|
|
24
24
|
import { NATIVE_CURRENCY, addressesFor, chainFor } from './chains.js';
|
|
@@ -780,7 +780,7 @@ export class PanalClient {
|
|
|
780
780
|
if (!base)
|
|
781
781
|
throw new X402Error(`El agente ${agent} no publica endpoint en su metadata.`);
|
|
782
782
|
try {
|
|
783
|
-
const url = await assertPublicUrl(
|
|
783
|
+
const url = await assertPublicUrl(rutaDeAgente(base, 'agent.json'), options);
|
|
784
784
|
const res = await fetchLimited(url, { timeoutMs: 10_000 });
|
|
785
785
|
if (res.status === 200) {
|
|
786
786
|
// `leerX402` entiende las dos formas. Antes esto solo miraba
|
|
@@ -791,13 +791,13 @@ export class PanalClient {
|
|
|
791
791
|
if (anunciado?.url)
|
|
792
792
|
return anunciado.url;
|
|
793
793
|
if (anunciado?.path)
|
|
794
|
-
return
|
|
794
|
+
return rutaDeAgente(base, anunciado.path);
|
|
795
795
|
}
|
|
796
796
|
}
|
|
797
797
|
catch {
|
|
798
798
|
/* sin tarjeta o ilegible: se cae a la convención */
|
|
799
799
|
}
|
|
800
|
-
return
|
|
800
|
+
return rutaDeAgente(base, 'x402/ask');
|
|
801
801
|
}
|
|
802
802
|
/** Retira lo acreditado en una moneda (patrón pull payment). */
|
|
803
803
|
async withdraw(currency = NATIVE_CURRENCY) {
|
package/dist/index.d.ts
CHANGED
|
@@ -39,7 +39,10 @@ export { ENVELOPE_HEADERS, DEFAULT_DEPTH, MAX_DEPTH, BudgetExhausted, DepthExhau
|
|
|
39
39
|
export type { CallEnvelope } from './envelope.js';
|
|
40
40
|
export type { UrlGuardOptions } from './net.js';
|
|
41
41
|
export { leerDireccion, leerMaxBriefChars, leerNiveles, leerX402, nivelPara } from './agent-card.js';
|
|
42
|
-
export type { AgentCard, FichaGetResult, FichaNivel, FichaPostBrief, FichaX402, Nivel } from './agent-card.js';
|
|
43
|
-
export { componerNivel, esTokenDeNivel, leerNivelDeSegmento, leerNivelesDeMetadata, NIVELES_EDITABLES, precioAWei, weiAPrecio, } from './niveles.js';
|
|
42
|
+
export type { AgentCard, FichaGetResult, FichaNivel, FichaPostAttachment, FichaPostBrief, FichaX402, Nivel, } from './agent-card.js';
|
|
43
|
+
export { componerNivel, conTextoDeLaFicha, esTokenDeNivel, leerNivelDeSegmento, leerNivelesDeMetadata, NIVELES_EDITABLES, precioAWei, weiAPrecio, } from './niveles.js';
|
|
44
|
+
export { esTokenDeTipo, leerTipo, leerTipoDeSegmento, tokenDeTipo } from './tipo.js';
|
|
45
|
+
export type { TipoDeAgente } from './tipo.js';
|
|
46
|
+
export { rutaDeAgente } from './net.js';
|
|
44
47
|
export { fichaEnIdioma, IDIOMAS, NOMBRE_IDIOMA, normalizarIdioma } from './idiomas.js';
|
|
45
48
|
export type { Idioma } from './idiomas.js';
|
package/dist/index.js
CHANGED
|
@@ -42,7 +42,13 @@ export { ENVELOPE_HEADERS, DEFAULT_DEPTH, MAX_DEPTH, BudgetExhausted, DepthExhau
|
|
|
42
42
|
export { leerDireccion, leerMaxBriefChars, leerNiveles, leerX402, nivelPara } from './agent-card.js';
|
|
43
43
|
// Los niveles escritos en el metadataURI on-chain. Mismo tipo `Nivel` que los
|
|
44
44
|
// de la ficha; en niveles.ts está por qué viven en los dos sitios.
|
|
45
|
-
export { componerNivel, esTokenDeNivel, leerNivelDeSegmento, leerNivelesDeMetadata, NIVELES_EDITABLES, precioAWei, weiAPrecio, } from './niveles.js';
|
|
45
|
+
export { componerNivel, conTextoDeLaFicha, esTokenDeNivel, leerNivelDeSegmento, leerNivelesDeMetadata, NIVELES_EDITABLES, precioAWei, weiAPrecio, } from './niveles.js';
|
|
46
|
+
// Quién hay al otro lado: una persona o un programa. Va en la misma cadena que
|
|
47
|
+
// los niveles, y por lo mismo lo tienen que reconocer todos los que la leen.
|
|
48
|
+
export { esTokenDeTipo, leerTipo, leerTipoDeSegmento, tokenDeTipo } from './tipo.js';
|
|
46
49
|
// La ficha en el idioma de quien la lee. En idiomas.ts está por qué traduce el
|
|
47
50
|
// propio agente y no un servicio de Panal.
|
|
51
|
+
// Unir una ruta con la URL de un agente. Ver por qué en `net.ts`: un agente
|
|
52
|
+
// puede vivir en un subcamino, y `new URL('/x', base)` se lo come.
|
|
53
|
+
export { rutaDeAgente } from './net.js';
|
|
48
54
|
export { fichaEnIdioma, IDIOMAS, NOMBRE_IDIOMA, normalizarIdioma } from './idiomas.js';
|
package/dist/net.d.ts
CHANGED
|
@@ -53,3 +53,18 @@ export declare function fetchLimited(url: URL | string, init?: RequestInit & {
|
|
|
53
53
|
headers: Headers;
|
|
54
54
|
text: string;
|
|
55
55
|
}>;
|
|
56
|
+
/**
|
|
57
|
+
* Una ruta del agente, colgando de DONDE está el agente.
|
|
58
|
+
*
|
|
59
|
+
* Parece una tontería y no lo es: `new URL('/brief/12', base)` descarta el
|
|
60
|
+
* camino de la base. Con un agente que vive en la raíz de su dominio
|
|
61
|
+
* —`https://bot.panal.lat`— da lo mismo y funcionó siempre; con uno que vive
|
|
62
|
+
* en un subcamino —`https://api.panal.lat/buzon/0xAAA`, que es donde reciben
|
|
63
|
+
* los que no tienen servidor propio— manda la petición a
|
|
64
|
+
* `https://api.panal.lat/brief/12`, que no es de nadie.
|
|
65
|
+
*
|
|
66
|
+
* Y lo que se rompe así no avisa: el 404 se lee como «ese agente no contesta»
|
|
67
|
+
* con el pago ya bloqueado, y a las 72 h se libera solo. Por eso la unión de
|
|
68
|
+
* rutas se hace en un sitio y no a mano en cada llamada.
|
|
69
|
+
*/
|
|
70
|
+
export declare function rutaDeAgente(base: string, ruta: string): string;
|
package/dist/net.js
CHANGED
|
@@ -148,3 +148,20 @@ export async function fetchLimited(url, init = {}) {
|
|
|
148
148
|
const { status, headers, bytes } = await fetchBytesLimited(url, init);
|
|
149
149
|
return { status, headers, text: new TextDecoder().decode(bytes) };
|
|
150
150
|
}
|
|
151
|
+
/**
|
|
152
|
+
* Una ruta del agente, colgando de DONDE está el agente.
|
|
153
|
+
*
|
|
154
|
+
* Parece una tontería y no lo es: `new URL('/brief/12', base)` descarta el
|
|
155
|
+
* camino de la base. Con un agente que vive en la raíz de su dominio
|
|
156
|
+
* —`https://bot.panal.lat`— da lo mismo y funcionó siempre; con uno que vive
|
|
157
|
+
* en un subcamino —`https://api.panal.lat/buzon/0xAAA`, que es donde reciben
|
|
158
|
+
* los que no tienen servidor propio— manda la petición a
|
|
159
|
+
* `https://api.panal.lat/brief/12`, que no es de nadie.
|
|
160
|
+
*
|
|
161
|
+
* Y lo que se rompe así no avisa: el 404 se lee como «ese agente no contesta»
|
|
162
|
+
* con el pago ya bloqueado, y a las 72 h se libera solo. Por eso la unión de
|
|
163
|
+
* rutas se hace en un sitio y no a mano en cada llamada.
|
|
164
|
+
*/
|
|
165
|
+
export function rutaDeAgente(base, ruta) {
|
|
166
|
+
return `${base.replace(/\/+$/, '')}/${ruta.replace(/^\/+/, '')}`;
|
|
167
|
+
}
|
package/dist/niveles.d.ts
CHANGED
|
@@ -100,3 +100,34 @@ export declare function componerNivel(nivel: {
|
|
|
100
100
|
maxAttachChars?: number | null;
|
|
101
101
|
maxAttachCharsTotal?: number | null;
|
|
102
102
|
}): string | null;
|
|
103
|
+
/**
|
|
104
|
+
* Los niveles de la cadena, con el texto de la ficha del agente.
|
|
105
|
+
*
|
|
106
|
+
* ───────────────────────────────────────────────────────────────────────────
|
|
107
|
+
* POR QUÉ HACE FALTA JUNTARLOS, EN VEZ DE ELEGIR UNO
|
|
108
|
+
*
|
|
109
|
+
* Un nivel es dos cosas distintas con dueños distintos:
|
|
110
|
+
*
|
|
111
|
+
* - El PRECIO y los topes. Es lo que se bloquea en el escrow, y tiene que
|
|
112
|
+
* salir de la cadena: son los únicos que siguen ahí con el bot caído, y los
|
|
113
|
+
* únicos que nadie puede cambiarte entre que miras y pagas.
|
|
114
|
+
*
|
|
115
|
+
* - El NOMBRE y la descripción. Son una etiqueta, y la ficha del agente es el
|
|
116
|
+
* único sitio donde pueden estar TRADUCIDAS: `?lang=fr` devuelve la ficha
|
|
117
|
+
* en francés, la cadena guarda una sola versión y traducirla costaría una
|
|
118
|
+
* transacción por idioma.
|
|
119
|
+
*
|
|
120
|
+
* Quedarse solo con los de la cadena —que es lo que se hizo primero— deja el
|
|
121
|
+
* escaparate entero en francés y los tres niveles de cada agente en español.
|
|
122
|
+
* Quedarse solo con los de la ficha devuelve el problema de antes: un agente
|
|
123
|
+
* caído se queda sin niveles y se le encarga el tamaño grande al precio del
|
|
124
|
+
* pequeño.
|
|
125
|
+
*
|
|
126
|
+
* SE EMPAREJAN POR PRECIO, que es la identidad de un nivel: el agente arma su
|
|
127
|
+
* ficha a partir de lo que tiene en la cadena, así que los importes coinciden
|
|
128
|
+
* exactos. Lo que no empareje se queda con su texto de la cadena, que es la
|
|
129
|
+
* respuesta correcta cuando la ficha dice otra cosa: enseñar el nombre de un
|
|
130
|
+
* nivel junto a un precio que no es el suyo sería peor que no traducirlo.
|
|
131
|
+
* ───────────────────────────────────────────────────────────────────────────
|
|
132
|
+
*/
|
|
133
|
+
export declare function conTextoDeLaFicha(enCadena: Nivel[], deLaFicha: Nivel[]): Nivel[];
|
package/dist/niveles.js
CHANGED
|
@@ -208,3 +208,49 @@ export function componerNivel(nivel) {
|
|
|
208
208
|
function entero(v) {
|
|
209
209
|
return typeof v === 'number' && Number.isInteger(v) && v > 0 ? String(v) : '';
|
|
210
210
|
}
|
|
211
|
+
/**
|
|
212
|
+
* Los niveles de la cadena, con el texto de la ficha del agente.
|
|
213
|
+
*
|
|
214
|
+
* ───────────────────────────────────────────────────────────────────────────
|
|
215
|
+
* POR QUÉ HACE FALTA JUNTARLOS, EN VEZ DE ELEGIR UNO
|
|
216
|
+
*
|
|
217
|
+
* Un nivel es dos cosas distintas con dueños distintos:
|
|
218
|
+
*
|
|
219
|
+
* - El PRECIO y los topes. Es lo que se bloquea en el escrow, y tiene que
|
|
220
|
+
* salir de la cadena: son los únicos que siguen ahí con el bot caído, y los
|
|
221
|
+
* únicos que nadie puede cambiarte entre que miras y pagas.
|
|
222
|
+
*
|
|
223
|
+
* - El NOMBRE y la descripción. Son una etiqueta, y la ficha del agente es el
|
|
224
|
+
* único sitio donde pueden estar TRADUCIDAS: `?lang=fr` devuelve la ficha
|
|
225
|
+
* en francés, la cadena guarda una sola versión y traducirla costaría una
|
|
226
|
+
* transacción por idioma.
|
|
227
|
+
*
|
|
228
|
+
* Quedarse solo con los de la cadena —que es lo que se hizo primero— deja el
|
|
229
|
+
* escaparate entero en francés y los tres niveles de cada agente en español.
|
|
230
|
+
* Quedarse solo con los de la ficha devuelve el problema de antes: un agente
|
|
231
|
+
* caído se queda sin niveles y se le encarga el tamaño grande al precio del
|
|
232
|
+
* pequeño.
|
|
233
|
+
*
|
|
234
|
+
* SE EMPAREJAN POR PRECIO, que es la identidad de un nivel: el agente arma su
|
|
235
|
+
* ficha a partir de lo que tiene en la cadena, así que los importes coinciden
|
|
236
|
+
* exactos. Lo que no empareje se queda con su texto de la cadena, que es la
|
|
237
|
+
* respuesta correcta cuando la ficha dice otra cosa: enseñar el nombre de un
|
|
238
|
+
* nivel junto a un precio que no es el suyo sería peor que no traducirlo.
|
|
239
|
+
* ───────────────────────────────────────────────────────────────────────────
|
|
240
|
+
*/
|
|
241
|
+
export function conTextoDeLaFicha(enCadena, deLaFicha) {
|
|
242
|
+
if (enCadena.length === 0 || deLaFicha.length === 0)
|
|
243
|
+
return enCadena;
|
|
244
|
+
return enCadena.map((n) => {
|
|
245
|
+
const igual = deLaFicha.find((f) => f.wei === n.wei);
|
|
246
|
+
if (!igual)
|
|
247
|
+
return n;
|
|
248
|
+
return {
|
|
249
|
+
...n,
|
|
250
|
+
// Solo se pisa lo que la ficha REALMENTE trae: un nivel con nombre no
|
|
251
|
+
// puede perderlo porque la ficha venga a medias.
|
|
252
|
+
name: igual.name ?? n.name,
|
|
253
|
+
description: igual.description ?? n.description,
|
|
254
|
+
};
|
|
255
|
+
});
|
|
256
|
+
}
|
package/dist/tipo.d.ts
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Panal — quién hay al otro lado: una persona o un programa.
|
|
3
|
+
*
|
|
4
|
+
* Un token más de los que viven en el `metadataURI` on-chain, junto a `bot:`,
|
|
5
|
+
* los de marca y los de nivel:
|
|
6
|
+
*
|
|
7
|
+
* Marta · Traduce contratos ES⇄FR · traducción · tipo:persona · bot:…
|
|
8
|
+
*
|
|
9
|
+
* POR QUÉ ESTÁ EN LA CADENA Y NO EN LA TARJETA
|
|
10
|
+
*
|
|
11
|
+
* Porque es lo que decide en qué mercado sale y con quién se le compara, y eso
|
|
12
|
+
* no puede depender de que un servidor conteste. Una persona que apaga el
|
|
13
|
+
* ordenador el viernes no se convierte en un bot el sábado.
|
|
14
|
+
*
|
|
15
|
+
* POR QUÉ NO SE ADIVINA
|
|
16
|
+
*
|
|
17
|
+
* Se podría intentar: quien usa el buzón de Panal parece una persona, quien
|
|
18
|
+
* tiene servidor propio parece un bot. Las dos cosas son falsas —un bot puede
|
|
19
|
+
* usar el buzón y una persona puede montarse un servidor—, y equivocarse aquí
|
|
20
|
+
* es etiquetar a alguien de lo que no es. Así que se declara, y quien no
|
|
21
|
+
* declara nada es lo que han sido todos los agentes registrados hasta hoy: un
|
|
22
|
+
* programa.
|
|
23
|
+
*
|
|
24
|
+
* LO QUE ESTE TOKEN NO ES
|
|
25
|
+
*
|
|
26
|
+
* No es una verificación. Nadie comprueba que detrás de `tipo:persona` haya
|
|
27
|
+
* una persona, igual que nadie comprueba que detrás de un nombre haya quien
|
|
28
|
+
* dice. Lo que hace es que la respuesta sea SUYA y esté firmada, en vez de que
|
|
29
|
+
* la deduzca el mercado por su cuenta.
|
|
30
|
+
*/
|
|
31
|
+
/** Quién trabaja: una persona, o un programa. */
|
|
32
|
+
export type TipoDeAgente = 'persona' | 'bot';
|
|
33
|
+
/**
|
|
34
|
+
* Qué dice un segmento, o `null` si no es uno de estos.
|
|
35
|
+
*
|
|
36
|
+
* Solo se reconocen los dos valores. `tipo:` con cualquier otra cosa detrás no
|
|
37
|
+
* es un tipo desconocido que haya que respetar: es texto que alguien escribió
|
|
38
|
+
* mal, y tratarlo como token lo borraría de su descripción sin decírselo.
|
|
39
|
+
*/
|
|
40
|
+
export declare function leerTipoDeSegmento(segmento: string): TipoDeAgente | null;
|
|
41
|
+
/** true si este segmento es un tipo. Para que los lectores de ficha lo aparten. */
|
|
42
|
+
export declare function esTokenDeTipo(segmento: string): boolean;
|
|
43
|
+
/**
|
|
44
|
+
* Quién hay detrás de esta ficha. Sin token, un programa.
|
|
45
|
+
*
|
|
46
|
+
* Ausente NO es «no se sabe» a efectos de enseñarlo: hay que ponerlo en algún
|
|
47
|
+
* mercado, y el sitio honrado para los diez agentes que ya estaban registrados
|
|
48
|
+
* antes de que esto existiera es el de programas, que es lo que son.
|
|
49
|
+
*/
|
|
50
|
+
export declare function leerTipo(metadataURI: string | null | undefined): TipoDeAgente;
|
|
51
|
+
/**
|
|
52
|
+
* El token que hay que escribir, o `null` si no hay que escribir ninguno.
|
|
53
|
+
*
|
|
54
|
+
* `bot` no escribe nada a propósito. Es lo que se supone sin token, así que
|
|
55
|
+
* escribirlo alarga la ficha de todos los agentes —y el gas de registrarlos—
|
|
56
|
+
* para no decir nada que no se supiera.
|
|
57
|
+
*/
|
|
58
|
+
export declare function tokenDeTipo(tipo: TipoDeAgente): string | null;
|
package/dist/tipo.js
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Panal — quién hay al otro lado: una persona o un programa.
|
|
3
|
+
*
|
|
4
|
+
* Un token más de los que viven en el `metadataURI` on-chain, junto a `bot:`,
|
|
5
|
+
* los de marca y los de nivel:
|
|
6
|
+
*
|
|
7
|
+
* Marta · Traduce contratos ES⇄FR · traducción · tipo:persona · bot:…
|
|
8
|
+
*
|
|
9
|
+
* POR QUÉ ESTÁ EN LA CADENA Y NO EN LA TARJETA
|
|
10
|
+
*
|
|
11
|
+
* Porque es lo que decide en qué mercado sale y con quién se le compara, y eso
|
|
12
|
+
* no puede depender de que un servidor conteste. Una persona que apaga el
|
|
13
|
+
* ordenador el viernes no se convierte en un bot el sábado.
|
|
14
|
+
*
|
|
15
|
+
* POR QUÉ NO SE ADIVINA
|
|
16
|
+
*
|
|
17
|
+
* Se podría intentar: quien usa el buzón de Panal parece una persona, quien
|
|
18
|
+
* tiene servidor propio parece un bot. Las dos cosas son falsas —un bot puede
|
|
19
|
+
* usar el buzón y una persona puede montarse un servidor—, y equivocarse aquí
|
|
20
|
+
* es etiquetar a alguien de lo que no es. Así que se declara, y quien no
|
|
21
|
+
* declara nada es lo que han sido todos los agentes registrados hasta hoy: un
|
|
22
|
+
* programa.
|
|
23
|
+
*
|
|
24
|
+
* LO QUE ESTE TOKEN NO ES
|
|
25
|
+
*
|
|
26
|
+
* No es una verificación. Nadie comprueba que detrás de `tipo:persona` haya
|
|
27
|
+
* una persona, igual que nadie comprueba que detrás de un nombre haya quien
|
|
28
|
+
* dice. Lo que hace es que la respuesta sea SUYA y esté firmada, en vez de que
|
|
29
|
+
* la deduzca el mercado por su cuenta.
|
|
30
|
+
*/
|
|
31
|
+
/** El prefijo del token, en minúsculas. */
|
|
32
|
+
const PREFIJO = 'tipo:';
|
|
33
|
+
/**
|
|
34
|
+
* Qué dice un segmento, o `null` si no es uno de estos.
|
|
35
|
+
*
|
|
36
|
+
* Solo se reconocen los dos valores. `tipo:` con cualquier otra cosa detrás no
|
|
37
|
+
* es un tipo desconocido que haya que respetar: es texto que alguien escribió
|
|
38
|
+
* mal, y tratarlo como token lo borraría de su descripción sin decírselo.
|
|
39
|
+
*/
|
|
40
|
+
export function leerTipoDeSegmento(segmento) {
|
|
41
|
+
const s = segmento.trim();
|
|
42
|
+
if (!s.toLowerCase().startsWith(PREFIJO))
|
|
43
|
+
return null;
|
|
44
|
+
const valor = s.slice(PREFIJO.length).trim().toLowerCase();
|
|
45
|
+
return valor === 'persona' || valor === 'bot' ? valor : null;
|
|
46
|
+
}
|
|
47
|
+
/** true si este segmento es un tipo. Para que los lectores de ficha lo aparten. */
|
|
48
|
+
export function esTokenDeTipo(segmento) {
|
|
49
|
+
return leerTipoDeSegmento(segmento) !== null;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Quién hay detrás de esta ficha. Sin token, un programa.
|
|
53
|
+
*
|
|
54
|
+
* Ausente NO es «no se sabe» a efectos de enseñarlo: hay que ponerlo en algún
|
|
55
|
+
* mercado, y el sitio honrado para los diez agentes que ya estaban registrados
|
|
56
|
+
* antes de que esto existiera es el de programas, que es lo que son.
|
|
57
|
+
*/
|
|
58
|
+
export function leerTipo(metadataURI) {
|
|
59
|
+
if (!metadataURI)
|
|
60
|
+
return 'bot';
|
|
61
|
+
for (const seg of metadataURI.split('·')) {
|
|
62
|
+
const tipo = leerTipoDeSegmento(seg);
|
|
63
|
+
if (tipo)
|
|
64
|
+
return tipo;
|
|
65
|
+
}
|
|
66
|
+
return 'bot';
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* El token que hay que escribir, o `null` si no hay que escribir ninguno.
|
|
70
|
+
*
|
|
71
|
+
* `bot` no escribe nada a propósito. Es lo que se supone sin token, así que
|
|
72
|
+
* escribirlo alarga la ficha de todos los agentes —y el gas de registrarlos—
|
|
73
|
+
* para no decir nada que no se supiera.
|
|
74
|
+
*/
|
|
75
|
+
export function tokenDeTipo(tipo) {
|
|
76
|
+
return tipo === 'persona' ? `${PREFIJO}persona` : null;
|
|
77
|
+
}
|
package/dist/types.js
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
* se veía al mirar la ficha en el marketplace.
|
|
9
9
|
*/
|
|
10
10
|
import { esTokenDeNivel } from './niveles.js';
|
|
11
|
+
import { esTokenDeTipo } from './tipo.js';
|
|
11
12
|
/** Estados de una tarea en el escrow, en el mismo orden que el enum de Solidity. */
|
|
12
13
|
export var TaskStatus;
|
|
13
14
|
(function (TaskStatus) {
|
|
@@ -170,6 +171,10 @@ export function parseAgentMetadata(metadataURI) {
|
|
|
170
171
|
// `leerNivelesDeMetadata`; aquí solo hace falta reconocerlos.
|
|
171
172
|
if (esTokenDeNivel(seg))
|
|
172
173
|
continue;
|
|
174
|
+
// Y quién hay detrás, por lo mismo: sin apartarlo, `tipo:persona` saldría
|
|
175
|
+
// anunciado como una skill de esa persona.
|
|
176
|
+
if (esTokenDeTipo(seg))
|
|
177
|
+
continue;
|
|
173
178
|
rest.push(seg);
|
|
174
179
|
}
|
|
175
180
|
// Los campos que falten quedan vacíos en vez de desplazar a los siguientes:
|