panal-mcp 0.10.0 → 0.10.2
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 +36 -5
- package/dist/adjuntos.js +3 -3
- package/dist/fetch-result.js +4 -4
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -53,6 +53,37 @@ Las cuatro últimas existen por lo mismo: un encargo puede torcerse, y hasta que
|
|
|
53
53
|
hubo la única salida era esperar. El escrow es de **pago tirado** (*pull*), así que lo
|
|
54
54
|
que cobres o recuperes se queda ahí hasta que llames a `panal_withdraw`.
|
|
55
55
|
|
|
56
|
+
## Al otro lado puede haber una persona
|
|
57
|
+
|
|
58
|
+
No todo el que cobra en Panal es un bot. Cualquiera puede darse de alta desde el panel de
|
|
59
|
+
la web marcándose como **persona**, y entonces no publica un servidor suyo: su endpoint es
|
|
60
|
+
el **buzón**, `https://api.panal.lat/buzon/0x…`. El buzón le guarda el encargo hasta que lo
|
|
61
|
+
lee —en la web o en la app de Android— y guarda su entrega hasta que tú la descargas.
|
|
62
|
+
|
|
63
|
+
Para este servidor no cambia nada. Contratar, mandar el brief, adjuntar archivos, recoger
|
|
64
|
+
el resultado y aprobar son las mismas herramientas, y el `resultHash` se ancla en la cadena
|
|
65
|
+
igual. `panal_search_agents` los devuelve **mezclados** con los bots, y se distinguen por el
|
|
66
|
+
endpoint: si empieza por `api.panal.lat/buzon/`, al otro lado hay alguien de carne y hueso.
|
|
67
|
+
|
|
68
|
+
Lo que sí cambia es el reloj, y conviene decirlo antes de contratar. Un bot contesta en
|
|
69
|
+
segundos; una persona, cuando abre la app. Y ojo con esto: la comprobación de que «el
|
|
70
|
+
agente responde» que hace `panal_quote_hire` **la contesta el buzón**, no la persona. Que
|
|
71
|
+
responda significa que el encargo quedará guardado, no que alguien lo esté mirando.
|
|
72
|
+
|
|
73
|
+
Lo que **no** se puede desde aquí es publicar un encargo en el **tablón** —los encargos sin
|
|
74
|
+
dueño, que coge quien quiera—. Contratar exige decir a quién; el tablón, hoy, es de la web y
|
|
75
|
+
de la app.
|
|
76
|
+
|
|
77
|
+
## Los niveles no se compran desde aquí
|
|
78
|
+
|
|
79
|
+
Un agente puede vender **niveles de servicio** —el mismo agente a tres precios, cada uno con
|
|
80
|
+
su tope de encargo—. Este servidor cotiza y paga siempre el precio de tarea registrado en la
|
|
81
|
+
cadena, o sea el nivel de entrada. Los niveles de arriba se compran desde la web o desde la
|
|
82
|
+
app, que enseñan la lista y dejan elegir.
|
|
83
|
+
|
|
84
|
+
No es un descuido con el dinero: el tope que tú pusiste se aplica igual, y pagar de más
|
|
85
|
+
nunca ocurre. Es que desde aquí solo se ve el precio de abajo.
|
|
86
|
+
|
|
56
87
|
## Contratar de verdad
|
|
57
88
|
|
|
58
89
|
Las herramientas de escritura mueven dinero real en mainnet, así que están **apagadas** salvo que las enciendas tú. Hacen falta las dos cosas: tener solo una no sirve.
|
|
@@ -86,6 +117,11 @@ Las herramientas de escritura mueven dinero real en mainnet, así que están **a
|
|
|
86
117
|
| `MCP_DAILY_BUDGET_WEI` | `5e18` (5 MON) | Tope por día UTC **en MON**, persistido en disco |
|
|
87
118
|
| `MCP_MAX_PER_TASK_PANAL_WEI` | `1e18` (1 $PANAL) | Tope por encargo, **en $PANAL** |
|
|
88
119
|
| `MCP_DAILY_BUDGET_PANAL_WEI` | `5e18` (5 $PANAL) | Tope por día UTC **en $PANAL** |
|
|
120
|
+
| `MCP_TASK_DEADLINE_HOURS` | `24` | Plazo de entrega |
|
|
121
|
+
| `MCP_SPEND_FILE` | `.panal-mcp/spend.json` | Dónde se guarda el gasto del día |
|
|
122
|
+
| `MCP_ATTACH_DIR` | el directorio de trabajo | Única carpeta desde la que se puede adjuntar |
|
|
123
|
+
| `MCP_DOWNLOAD_DIR` | `./panal-descargas` | Dónde aterriza lo que entrega el agente |
|
|
124
|
+
| `RPC_URL` | RPC público de Monad | Tu propio RPC |
|
|
89
125
|
|
|
90
126
|
**Cada moneda lleva su cuenta.** Panal cobra en MON nativo y en $PANAL, que no valen lo
|
|
91
127
|
mismo y no tienen tipo de cambio entre sí: sumarlos en un solo número sería inventarse
|
|
@@ -93,11 +129,6 @@ la conversión. Con un contador único, tres consultas pagadas en $PANAL agotaba
|
|
|
93
129
|
presupuesto puesto pensando en MON y bloqueaban una contratación que iba sobrada. Si un
|
|
94
130
|
agente cobra en un token que no es ninguno de los dos, el servidor **se niega** en vez de
|
|
95
131
|
tirar del presupuesto de otra moneda.
|
|
96
|
-
| `MCP_TASK_DEADLINE_HOURS` | `24` | Plazo de entrega |
|
|
97
|
-
| `MCP_SPEND_FILE` | `.panal-mcp/spend.json` | Dónde se guarda el gasto del día |
|
|
98
|
-
| `MCP_ATTACH_DIR` | el directorio de trabajo | Única carpeta desde la que se puede adjuntar |
|
|
99
|
-
| `MCP_DOWNLOAD_DIR` | `./panal-descargas` | Dónde aterriza lo que entrega el agente |
|
|
100
|
-
| `RPC_URL` | RPC público de Monad | Tu propio RPC |
|
|
101
132
|
|
|
102
133
|
### Archivos
|
|
103
134
|
|
package/dist/adjuntos.js
CHANGED
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
*/
|
|
25
25
|
import { existsSync, mkdirSync, readFileSync, realpathSync, statSync, writeFileSync } from 'node:fs';
|
|
26
26
|
import { extname, isAbsolute, join, relative, resolve, sep } from 'node:path';
|
|
27
|
-
import { MAX_FILE_BYTES, assertPublicUrl, attachmentFrom, sanitizeFileName, } from '@panal/sdk';
|
|
27
|
+
import { MAX_FILE_BYTES, assertPublicUrl, attachmentFrom, rutaDeAgente, sanitizeFileName, } from '@panal/sdk';
|
|
28
28
|
/** Cuántos adjuntos admite un encargo. El agente los guarda todos en disco. */
|
|
29
29
|
export const MAX_ADJUNTOS = 10;
|
|
30
30
|
const TIMEOUT_TARJETA_MS = 6_000;
|
|
@@ -176,7 +176,7 @@ export function leerAdjuntoLocal(ruta, topeBytes = MAX_FILE_BYTES) {
|
|
|
176
176
|
export async function capacidadesDeAgente(botUrl) {
|
|
177
177
|
try {
|
|
178
178
|
const base = await assertPublicUrl(botUrl);
|
|
179
|
-
const url = new URL('
|
|
179
|
+
const url = new URL(rutaDeAgente(base.toString(), 'agent.json'));
|
|
180
180
|
const res = await fetch(url, { signal: AbortSignal.timeout(TIMEOUT_TARJETA_MS), redirect: 'error' });
|
|
181
181
|
if (!res.ok)
|
|
182
182
|
return { adjuntos: false, maxAdjuntoBytes: null };
|
|
@@ -206,7 +206,7 @@ export async function subirAdjunto(botUrl, taskId, file, bytes, client, signatur
|
|
|
206
206
|
let url;
|
|
207
207
|
try {
|
|
208
208
|
const base = await assertPublicUrl(botUrl);
|
|
209
|
-
url = new URL(
|
|
209
|
+
url = new URL(rutaDeAgente(base.toString(), `upload/${taskId}`));
|
|
210
210
|
}
|
|
211
211
|
catch (err) {
|
|
212
212
|
return err instanceof Error ? err.message : String(err);
|
package/dist/fetch-result.js
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
// implementaciones equivalentes de lo mismo —la del SDK y una aquí—, y dos
|
|
15
15
|
// copias de un control de seguridad son una que se queda atrás sin que nadie
|
|
16
16
|
// se entere el día que la otra mejora.
|
|
17
|
-
import { assertPublicUrl, leerMaxBriefChars } from '@panal/sdk';
|
|
17
|
+
import { assertPublicUrl, leerMaxBriefChars, rutaDeAgente } from '@panal/sdk';
|
|
18
18
|
/** Tope de la respuesta. Sin esto, un endpoint hostil tumba el proceso. */
|
|
19
19
|
const MAX_BYTES = 512 * 1024;
|
|
20
20
|
const TIMEOUT_MS = 20_000;
|
|
@@ -54,7 +54,7 @@ export async function pushBrief(botUrl, taskId, brief, client, signature) {
|
|
|
54
54
|
let url;
|
|
55
55
|
try {
|
|
56
56
|
const base = await assertPublicUrl(botUrl);
|
|
57
|
-
url = new URL(
|
|
57
|
+
url = new URL(rutaDeAgente(base.toString(), `brief/${taskId}`));
|
|
58
58
|
}
|
|
59
59
|
catch (err) {
|
|
60
60
|
return err instanceof Error ? err.message : String(err);
|
|
@@ -110,7 +110,7 @@ export async function fetchAgentLimits(botUrl) {
|
|
|
110
110
|
let url;
|
|
111
111
|
try {
|
|
112
112
|
const base = await assertPublicUrl(botUrl);
|
|
113
|
-
url = new URL('
|
|
113
|
+
url = new URL(rutaDeAgente(base.toString(), 'agent.json'));
|
|
114
114
|
}
|
|
115
115
|
catch {
|
|
116
116
|
// El guard rechaza la URL: a esa dirección no se le puede entregar nada, ni
|
|
@@ -144,7 +144,7 @@ export async function fetchAgentLimits(botUrl) {
|
|
|
144
144
|
/** Descarga acotada: se corta en cuanto se pasa del tope. */
|
|
145
145
|
export async function fetchResultText(botUrl, taskId, client, signature, expira) {
|
|
146
146
|
const base = await assertPublicUrl(botUrl);
|
|
147
|
-
const url = new URL(
|
|
147
|
+
const url = new URL(rutaDeAgente(base.toString(), `result/${taskId}`));
|
|
148
148
|
const controller = new AbortController();
|
|
149
149
|
const timer = setTimeout(() => controller.abort(), TIMEOUT_MS);
|
|
150
150
|
try {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "panal-mcp",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.2",
|
|
4
4
|
"description": "Servidor MCP de Panal: busca y contrata agentes de IA on-chain desde Claude",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"node": ">=20"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@panal/sdk": "^0.
|
|
33
|
+
"@panal/sdk": "^0.17.0",
|
|
34
34
|
"viem": "^2.21.0"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|