@panal/sdk 0.10.1 → 0.11.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 +121 -0
- package/dist/agent-card.js +54 -0
- package/dist/client.js +6 -2
- package/dist/index.d.ts +2 -0
- package/dist/index.js +3 -0
- package/package.json +2 -2
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* La ficha que un agente sirve en `GET /agent.json`.
|
|
3
|
+
*
|
|
4
|
+
* POR QUÉ ESTE ARCHIVO EXISTE
|
|
5
|
+
*
|
|
6
|
+
* Había dos formatos. El bot colocaba el cobro por llamada en
|
|
7
|
+
* `endpoints.x402Ask`; la plantilla lo ponía en la raíz, como `x402Ask`. Los
|
|
8
|
+
* dos servían la misma información y ningún lector veía las dos, porque cada
|
|
9
|
+
* uno parseaba con un tipo escrito a mano allí donde hacía falta.
|
|
10
|
+
*
|
|
11
|
+
* No fue un descuido de nadie: el tipo `AgentJson` vivía dentro del bot, así
|
|
12
|
+
* que la plantilla —que no depende del bot— no tenía de dónde copiarlo y
|
|
13
|
+
* escribió su propio objeto. Dos implementaciones honestas de una idea que
|
|
14
|
+
* nunca se escribió en un sitio común divergen solas.
|
|
15
|
+
*
|
|
16
|
+
* Aquí está esa idea, en el paquete del que ya dependen la plantilla y el MCP.
|
|
17
|
+
* Quien sirva una ficha, que la sirva con esta forma; quien la lea, que la lea
|
|
18
|
+
* con `leerX402` y `leerMaxBriefChars`, que entienden también la forma vieja.
|
|
19
|
+
*
|
|
20
|
+
* COMPATIBILIDAD
|
|
21
|
+
*
|
|
22
|
+
* Hay agentes desplegados sirviendo el formato antiguo, y no se les puede
|
|
23
|
+
* pedir que se actualicen para seguir siendo contratables. Los lectores
|
|
24
|
+
* aceptan las dos formas y lo seguirán haciendo: quien escribe se moderniza,
|
|
25
|
+
* quien lee perdona. Es la misma regla que ya seguía `agentAddress`.
|
|
26
|
+
*/
|
|
27
|
+
import type { Address } from 'viem';
|
|
28
|
+
/** Cobro por llamada (x402), tal y como lo anuncia un agente. */
|
|
29
|
+
export interface FichaX402 {
|
|
30
|
+
method?: 'POST';
|
|
31
|
+
/** Ruta relativa. `url` gana si están las dos. */
|
|
32
|
+
path?: string;
|
|
33
|
+
url?: string;
|
|
34
|
+
scheme?: string;
|
|
35
|
+
/** Token ERC-20 en el que cobra. */
|
|
36
|
+
asset?: Address;
|
|
37
|
+
assetSymbol?: string;
|
|
38
|
+
/** Precio por llamada, en wei del token, como cadena decimal. */
|
|
39
|
+
amount?: string;
|
|
40
|
+
payTo?: Address;
|
|
41
|
+
howTo?: string;
|
|
42
|
+
}
|
|
43
|
+
/** Cómo mandarle el encargo a un agente, y cuánto texto acepta. */
|
|
44
|
+
export interface FichaPostBrief {
|
|
45
|
+
method?: 'POST';
|
|
46
|
+
path?: string;
|
|
47
|
+
signMessage?: string;
|
|
48
|
+
body?: string;
|
|
49
|
+
/**
|
|
50
|
+
* Tope de caracteres del encargo.
|
|
51
|
+
*
|
|
52
|
+
* Publicarlo es lo que evita que un cliente bloquee el pago con un encargo
|
|
53
|
+
* que el agente va a rechazar. Ausente significa NO LO DICE, que no es lo
|
|
54
|
+
* mismo que «no hay tope»: tratarlo como ilimitado es volver a averiguarlo
|
|
55
|
+
* pagando.
|
|
56
|
+
*/
|
|
57
|
+
maxBriefChars?: number;
|
|
58
|
+
}
|
|
59
|
+
/** Cómo descargar el resultado ya entregado. */
|
|
60
|
+
export interface FichaGetResult {
|
|
61
|
+
method?: 'GET';
|
|
62
|
+
path?: string;
|
|
63
|
+
signMessage?: string;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* La ficha completa. Casi todo es opcional a propósito: los dos motores tienen
|
|
67
|
+
* capacidades distintas —el de la plantilla no lee el registry al servirla, y
|
|
68
|
+
* el del bot sí— y un esquema que obligue a rellenar lo que no se sabe termina
|
|
69
|
+
* rellenándose con mentiras.
|
|
70
|
+
*/
|
|
71
|
+
export interface AgentCard {
|
|
72
|
+
/** La dirección on-chain que este dominio declara suya. Es lo que verifica. */
|
|
73
|
+
agent?: Address;
|
|
74
|
+
/** Alias antiguo de `agent`. Se sigue leyendo; no lo escribas en fichas nuevas. */
|
|
75
|
+
agentAddress?: Address;
|
|
76
|
+
protocol?: 'panal';
|
|
77
|
+
network?: string;
|
|
78
|
+
chainId?: number;
|
|
79
|
+
name?: string;
|
|
80
|
+
description?: string;
|
|
81
|
+
skills?: string[];
|
|
82
|
+
price?: {
|
|
83
|
+
amountWei?: string;
|
|
84
|
+
currency?: Address;
|
|
85
|
+
symbol?: string;
|
|
86
|
+
} | null;
|
|
87
|
+
active?: boolean | null;
|
|
88
|
+
contracts?: {
|
|
89
|
+
escrow?: Address;
|
|
90
|
+
registry?: Address;
|
|
91
|
+
token?: Address;
|
|
92
|
+
};
|
|
93
|
+
endpoints?: {
|
|
94
|
+
base?: string | null;
|
|
95
|
+
postBrief?: FichaPostBrief;
|
|
96
|
+
getResult?: FichaGetResult;
|
|
97
|
+
x402Ask?: FichaX402;
|
|
98
|
+
indexer?: string | null;
|
|
99
|
+
};
|
|
100
|
+
/** Alias ANTIGUO de `endpoints.x402Ask`. Se lee; no se escribe. */
|
|
101
|
+
x402Ask?: FichaX402;
|
|
102
|
+
howToHire?: string[];
|
|
103
|
+
}
|
|
104
|
+
/** La dirección que la ficha declara suya, mirando también el alias viejo. */
|
|
105
|
+
export declare function leerDireccion(card: unknown): string | null;
|
|
106
|
+
/**
|
|
107
|
+
* El bloque de cobro por llamada, venga en el sitio nuevo o en el viejo.
|
|
108
|
+
*
|
|
109
|
+
* El sitio canónico gana si están los dos: un agente que sirva ambos está en
|
|
110
|
+
* mitad de una migración, y el nuevo es el que va a seguir manteniendo.
|
|
111
|
+
*/
|
|
112
|
+
export declare function leerX402(card: unknown): FichaX402 | null;
|
|
113
|
+
/**
|
|
114
|
+
* El tope de caracteres del encargo, o `null` si la ficha no lo dice.
|
|
115
|
+
*
|
|
116
|
+
* `null` es NO LO SÉ y hay que tratarlo así. La ficha la sirve un desconocido,
|
|
117
|
+
* así que solo cuenta un entero positivo: un 0 o un negativo harían imposible
|
|
118
|
+
* cualquier encargo, y eso lo decide el agente bajando su tope, no mandando
|
|
119
|
+
* basura en un campo.
|
|
120
|
+
*/
|
|
121
|
+
export declare function leerMaxBriefChars(card: unknown): number | null;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* La ficha que un agente sirve en `GET /agent.json`.
|
|
3
|
+
*
|
|
4
|
+
* POR QUÉ ESTE ARCHIVO EXISTE
|
|
5
|
+
*
|
|
6
|
+
* Había dos formatos. El bot colocaba el cobro por llamada en
|
|
7
|
+
* `endpoints.x402Ask`; la plantilla lo ponía en la raíz, como `x402Ask`. Los
|
|
8
|
+
* dos servían la misma información y ningún lector veía las dos, porque cada
|
|
9
|
+
* uno parseaba con un tipo escrito a mano allí donde hacía falta.
|
|
10
|
+
*
|
|
11
|
+
* No fue un descuido de nadie: el tipo `AgentJson` vivía dentro del bot, así
|
|
12
|
+
* que la plantilla —que no depende del bot— no tenía de dónde copiarlo y
|
|
13
|
+
* escribió su propio objeto. Dos implementaciones honestas de una idea que
|
|
14
|
+
* nunca se escribió en un sitio común divergen solas.
|
|
15
|
+
*
|
|
16
|
+
* Aquí está esa idea, en el paquete del que ya dependen la plantilla y el MCP.
|
|
17
|
+
* Quien sirva una ficha, que la sirva con esta forma; quien la lea, que la lea
|
|
18
|
+
* con `leerX402` y `leerMaxBriefChars`, que entienden también la forma vieja.
|
|
19
|
+
*
|
|
20
|
+
* COMPATIBILIDAD
|
|
21
|
+
*
|
|
22
|
+
* Hay agentes desplegados sirviendo el formato antiguo, y no se les puede
|
|
23
|
+
* pedir que se actualicen para seguir siendo contratables. Los lectores
|
|
24
|
+
* aceptan las dos formas y lo seguirán haciendo: quien escribe se moderniza,
|
|
25
|
+
* quien lee perdona. Es la misma regla que ya seguía `agentAddress`.
|
|
26
|
+
*/
|
|
27
|
+
/** La dirección que la ficha declara suya, mirando también el alias viejo. */
|
|
28
|
+
export function leerDireccion(card) {
|
|
29
|
+
const c = card;
|
|
30
|
+
const dir = typeof c?.agent === 'string' ? c.agent : typeof c?.agentAddress === 'string' ? c.agentAddress : '';
|
|
31
|
+
return dir || null;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* El bloque de cobro por llamada, venga en el sitio nuevo o en el viejo.
|
|
35
|
+
*
|
|
36
|
+
* El sitio canónico gana si están los dos: un agente que sirva ambos está en
|
|
37
|
+
* mitad de una migración, y el nuevo es el que va a seguir manteniendo.
|
|
38
|
+
*/
|
|
39
|
+
export function leerX402(card) {
|
|
40
|
+
const c = card;
|
|
41
|
+
return c?.endpoints?.x402Ask ?? c?.x402Ask ?? null;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* El tope de caracteres del encargo, o `null` si la ficha no lo dice.
|
|
45
|
+
*
|
|
46
|
+
* `null` es NO LO SÉ y hay que tratarlo así. La ficha la sirve un desconocido,
|
|
47
|
+
* así que solo cuenta un entero positivo: un 0 o un negativo harían imposible
|
|
48
|
+
* cualquier encargo, y eso lo decide el agente bajando su tope, no mandando
|
|
49
|
+
* basura en un campo.
|
|
50
|
+
*/
|
|
51
|
+
export function leerMaxBriefChars(card) {
|
|
52
|
+
const max = card?.endpoints?.postBrief?.maxBriefChars;
|
|
53
|
+
return typeof max === 'number' && Number.isInteger(max) && max > 0 ? max : null;
|
|
54
|
+
}
|
package/dist/client.js
CHANGED
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
*/
|
|
18
18
|
import { createPublicClient, createWalletClient, formatEther, getAddress, http, keccak256, toBytes } from 'viem';
|
|
19
19
|
import { erc20Abi, escrowAbi, namesAbi, registryAbi } from './abis.js';
|
|
20
|
+
import { leerX402 } from './agent-card.js';
|
|
20
21
|
import { assertPublicUrl, fetchLimited } from './net.js';
|
|
21
22
|
import { X402Error, payAndAsk, quoteAsk } from './x402.js';
|
|
22
23
|
import { descend, newEnvelope, remainingBudget } from './envelope.js';
|
|
@@ -753,8 +754,11 @@ export class PanalClient {
|
|
|
753
754
|
const url = await assertPublicUrl(new URL('/agent.json', base).toString(), options);
|
|
754
755
|
const res = await fetchLimited(url, { timeoutMs: 10_000 });
|
|
755
756
|
if (res.status === 200) {
|
|
756
|
-
|
|
757
|
-
|
|
757
|
+
// `leerX402` entiende las dos formas. Antes esto solo miraba
|
|
758
|
+
// `endpoints.x402Ask`, así que con la ficha de un agente de plantilla
|
|
759
|
+
// no encontraba nada y caía a la convención: funcionaba de casualidad,
|
|
760
|
+
// y solo mientras el agente escuchara justo en /x402/ask.
|
|
761
|
+
const anunciado = leerX402(JSON.parse(res.text));
|
|
758
762
|
if (anunciado?.url)
|
|
759
763
|
return anunciado.url;
|
|
760
764
|
if (anunciado?.path)
|
package/dist/index.d.ts
CHANGED
|
@@ -36,3 +36,5 @@ export type { SettleDeps, SettleResult, X402Payment, X402ServerAccept, X402Serve
|
|
|
36
36
|
export { ENVELOPE_HEADERS, DEFAULT_DEPTH, MAX_DEPTH, BudgetExhausted, DepthExhausted, LoopDetected, assertCanServe, descend, envelopeHeaders, newEnvelope, parseEnvelope, remainingBudget, } from './envelope.js';
|
|
37
37
|
export type { CallEnvelope } from './envelope.js';
|
|
38
38
|
export type { UrlGuardOptions } from './net.js';
|
|
39
|
+
export { leerDireccion, leerMaxBriefChars, leerX402 } from './agent-card.js';
|
|
40
|
+
export type { AgentCard, FichaGetResult, FichaPostBrief, FichaX402 } from './agent-card.js';
|
package/dist/index.js
CHANGED
|
@@ -33,3 +33,6 @@ export { FILES_BLOCK, MAX_FILE_BYTES, FileVerificationError, appendFilesManifest
|
|
|
33
33
|
export { X402_VERSION, X402_SERVER_SCHEME, buildQuote, enqueueByPayer, parsePaymentHeader, permitNonce, permitTypedData, readPermitDomain, resourceId, splitSignature, verifyAndSettle, } from './x402-server.js';
|
|
34
34
|
// El sobre que viaja entre agentes: profundidad, presupuesto y detección de ciclos.
|
|
35
35
|
export { ENVELOPE_HEADERS, DEFAULT_DEPTH, MAX_DEPTH, BudgetExhausted, DepthExhausted, LoopDetected, assertCanServe, descend, envelopeHeaders, newEnvelope, parseEnvelope, remainingBudget, } from './envelope.js';
|
|
36
|
+
// La ficha de GET /agent.json: un solo formato, y lectores que perdonan el
|
|
37
|
+
// antiguo. En agent-card.ts está por qué llegó a haber dos.
|
|
38
|
+
export { leerDireccion, leerMaxBriefChars, leerX402 } from './agent-card.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@panal/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.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/x402.test.ts && tsx test/x402-server.test.ts && tsx test/envelope.test.ts && tsx test/files.test.ts && tsx test/skill.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 && tsx test/agent-card.test.ts",
|
|
49
49
|
"test:nombres": "tsx test/nombres.test.ts"
|
|
50
50
|
}
|
|
51
51
|
}
|