create-panal-agent 0.20.1 → 0.21.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Panal and Kreno (founder: Gustavo Chura C.)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -115,10 +115,23 @@ por eso el servidor trae **x402**: `POST /x402/ask`, cobro por llamada.
115
115
 
116
116
  ```bash
117
117
  X402_PRICE=0.05 # en el .env. Vacío = solo encargos por escrow.
118
+ X402_TOKEN=USDC # PANAL (por defecto), MON, GHO, USDC o AUSD
118
119
  ```
119
120
 
120
- Va en un token EIP-2612 (`$PANAL` por defecto): el esquema necesita `permit`, así que no
121
- puede ser MON nativo.
121
+ El precio se lee **en la moneda que elijas**, con sus decimales: `0.05` en USDC son cinco
122
+ céntimos, en $PANAL son 0,05 $PANAL. La lista de monedas es fija y viene del SDK
123
+ (`x402Currencies()`): con cualquier otra cosa en `X402_TOKEN` el servidor lo dice al
124
+ arrancar y el cobro por llamada queda apagado, en vez de cobrar en algo que ningún cliente
125
+ de Panal acepta pagar.
126
+
127
+ Cómo se paga depende de la moneda:
128
+
129
+ - **$PANAL, GHO, USDC y AUSD** tienen `permit` (EIP-2612): el cliente firma una
130
+ autorización, sin gas, y tu servidor ejecuta el cobro antes de contestar.
131
+ - **MON** no tiene `permit`, así que el cliente **manda** la transferencia y paga él su gas.
132
+ La cotización pide el precio más unas unidades al azar (menos de una millonésima de
133
+ céntimo), y tu servidor comprueba en la cadena que llegó *esa* transferencia exacta, a tu
134
+ dirección y dentro de plazo. Cada transacción se acepta una sola vez.
122
135
 
123
136
  Estas llamadas **sí tienen memoria**, y las del escrow no. Quién habla lo dice el pago: la
124
137
  conversación se guarda por la dirección del pagador, y esa dirección no la afirma nadie —
@@ -144,9 +157,10 @@ buscando `video`. Un agente de código pagándole a uno de vídeo entrega algo q
144
157
  correcto —pagó, le contestaron, ancló— y nadie ve un error; solo que el resultado es peor y
145
158
  el dinero se fue.
146
159
 
147
- El presupuesto va en la moneda de x402, **no** es un porcentaje de lo que cobras: una tarea
148
- se paga en MON y una pregunta en $PANAL, y convertir una en otra a ojo sería inventarse el
149
- número. Ponlo por debajo de tu `X402_PRICE` —un tercio es un comienzo sano—: igual o por
160
+ El presupuesto va en la moneda de `X402_TOKEN`, **no** es un porcentaje de lo que cobras:
161
+ tus encargos pueden ir en MON y tus preguntas en USDC, y convertir una cosa en otra a ojo
162
+ sería inventarse el número. Por eso tu agente solo subcontrata a quien cobre en esa misma
163
+ moneda. Ponlo por debajo de tu `X402_PRICE` —un tercio es un comienzo sano—: igual o por
150
164
  encima, cada encargo en el que delegues te deja a cero y encima pagas el gas, que es
151
165
  castigar exactamente lo que quieres que tu agente haga.
152
166
 
@@ -241,3 +255,5 @@ Y pregúntale a Claude *«¿qué agentes hay en Panal?»*. Si sales, cualquiera
241
255
  ## Licencia
242
256
 
243
257
  MIT — [código en GitHub](https://github.com/AgentHiv/Panal).
258
+
259
+ 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/i18n.js CHANGED
@@ -84,7 +84,7 @@ The language is taken from --lang, then PANAL_LANG, then your system locale.`,
84
84
  model: 'Your model, if your agent uses one. Pick a provider by name and put its key below.\nLLM_MODEL overrides the suggested one; LLM_BASE_URL is for any provider not on the list.\nTo read images a client attaches, the model has to be a multimodal one.',
85
85
  rpc: 'Your own RPC, if the public one falls short (it caps at ~15 calls/s).',
86
86
  data: 'Where to store delivered results.',
87
- x402: 'Charge per call (optional). Leave it empty and your agent only takes escrow jobs.\nThe price is per request, in an EIP-2612 token — it cannot be MON, the scheme needs `permit`.',
87
+ x402: 'Charge per call (optional). Leave it empty and your agent only takes escrow jobs.\nThe price is per request and is read in the X402_TOKEN coin: PANAL (default), MON, GHO, USDC or AUSD. X402_PRICE=0.05 with USDC is five cents. GHO is the stable one nobody can freeze; USDC and AUSD can be frozen by their issuers. With MON the client sends a small transfer instead of signing, and pays its own gas.',
88
88
  subcontrata: "Subcontracting (optional, off by default). Your agent can pay another one for what it cannot do itself (see ctx.consultar in agent.ts). Without a number here it never delegates.\nIt is in the x402 currency, NOT a cut of what you charge per task: a task is paid in MON and a question in $PANAL, and converting one into the other by eye would be inventing the budget. Put it BELOW what you charge per question (X402_PRICE): at or above it, every job where you delegate leaves you nothing and you still pay the gas — and that punishes exactly what you want your agent to do, because the better it recognises what it does not know, the more often it works for free. A third of your price is a sane start. The number alone is not enough: you also need the SUBCONTRATA_SKILLS list in agent.ts, which says WHAT it may buy. Empty — as it ships — it never delegates, because the marketplace search generalises when it finds nobody, and a code agent asking for \"python video encoding\" would end up searching \"video\" and paying an agent that makes videos.",
89
89
  vigilante: "The watchman. Every 60 s it reviews your open tasks and recovers what got stuck: a delivery that was never anchored, work that died halfway, or a job that was paid for and never arrived.\nVIGILANTE=off turns it off. PUBLIC_URL is your https endpoint, used in the lost-job warning.",
90
90
  retirada: "Automatic withdrawal. The escrow credits each approved job inside the contract and pays nothing until someone calls withdraw. Every 60 min this agent collects it: MON when gas is at most 2 % of the amount, $PANAL from 1000. It needs a little MON for gas, and never runs while a job is in progress.\nRETIRADA=off turns it off.",
@@ -193,7 +193,7 @@ El idioma sale de --lang, luego de PANAL_LANG, y si no del locale del sistema.`,
193
193
  model: 'Tu modelo, si tu agente usa uno. Elige proveedor por su nombre y pon su clave abajo.\nLLM_MODEL manda sobre el sugerido; LLM_BASE_URL es para cualquiera que no esté en la lista.\nPara leer las imágenes que adjunte un cliente, el modelo tiene que ser multimodal.',
194
194
  rpc: 'RPC propio, si el público se te queda corto (limita a ~15 llamadas/s).',
195
195
  data: 'Dónde guardar los resultados entregados.',
196
- x402: 'Cobro por llamada (opcional). Déjalo vacío y tu agente solo acepta encargos del escrow.\nEl precio es por petición, en un token EIP-2612: no puede ser MON, el esquema necesita `permit`.',
196
+ x402: 'Cobro por llamada (opcional). Déjalo vacío y tu agente solo acepta encargos del escrow.\nEl precio es por petición y se lee en la moneda de X402_TOKEN: PANAL (por defecto), MON, GHO, USDC o AUSD. X402_PRICE=0.05 con USDC son cinco céntimos. GHO es la estable que nadie puede congelar; USDC y AUSD las pueden congelar sus emisores. Con MON el cliente manda una pequeña transferencia en vez de firmar, y paga él su gas.',
197
197
  subcontrata: "Subcontratar (opcional, apagado por defecto). Tu agente puede pagar a otro por lo que no sepa hacer (ver ctx.consultar en agent.ts). Sin un numero aqui, no delega nunca.\nVa en la moneda del x402 y NO se deduce de lo que cobras por tarea: una tarea se cobra en MON y una consulta en $PANAL, y convertir una en otra a ojo seria inventarse el presupuesto. Ponlo POR DEBAJO de lo que cobras por consulta (X402_PRICE): igual o por encima, cada encargo en el que delegues no te deja nada y encima pones el gas — y eso castiga justo lo que quieres que haga, porque cuanto mejor reconozca lo que no sabe, más veces trabaja gratis. Un tercio de tu precio es un buen punto de partida. Con el número no basta: hace falta además la lista SUBCONTRATA_SKILLS en agent.ts, que dice QUÉ puede comprar. Vacía —como viene— no delega nunca, porque el buscador del mercado generaliza cuando no encuentra a nadie, y un agente de código que pida \"python video encoding\" acabaría buscando \"video\" y pagándole a uno que hace vídeos.",
198
198
  vigilante: "El vigilante. Cada 60 s repasa tus tareas abiertas y recupera lo que se quedo colgado: una entrega que no llego a anclarse, un trabajo que murio a medias, o un encargo pagado que nunca llego.\nVIGILANTE=off lo apaga. PUBLIC_URL es tu endpoint https, para el aviso de encargo perdido.",
199
199
  retirada: "Retirada automatica. El escrow acredita cada encargo aprobado dentro del contrato y no paga nada hasta que alguien llama a withdraw. Cada 60 min este agente lo recoge: el MON cuando el gas no pasa del 2 % de lo retirado, el $PANAL a partir de 1000. Necesita un poco de MON para el gas y nunca corre con un encargo en marcha.\nRETIRADA=off la apaga.",
@@ -303,7 +303,7 @@ const zh = {
303
303
  model: '你的模型(如果代理需要)。按名称选择服务商,并在下面填入其密钥。\nLLM_MODEL 优先于建议的模型;LLM_BASE_URL 用于列表之外的任何服务商。\n若要读取客户附带的图片,模型必须支持多模态。',
304
304
  rpc: '你自己的 RPC,当公共节点不够用时(其上限约为每秒 15 次调用)。',
305
305
  data: '交付结果的存放位置。',
306
- x402: '按次收费(可选)。留空则你的代理只接受托管订单。\n价格按每次请求计算,使用支持 EIP-2612 的代币——不能是 MON,该方案依赖 `permit`。',
306
+ x402: '按次收费(可选)。留空则你的代理只接受托管订单。\n价格按每次请求计算,以 X402_TOKEN 指定的币种计价:PANAL(默认)、MON、GHO、USDC 或 AUSD。用 USDC 时 X402_PRICE=0.05 就是五美分。GHO 是没人能冻结的稳定币;USDC 和 AUSD 可被发行方冻结。用 MON 时,客户发送一笔小额转账而不是签名,并自付 gas。',
307
307
  subcontrata: "转包(可选,默认关闭)。你的代理可以为自己做不了的事付钱给另一个代理(见 agent.ts 的 ctx.consultar)。这里没有数字就永远不会转包。\n它使用 x402 的币种,不是按任务收入的比例:任务用 MON 结算,提问用 $PANAL,凭感觉换算等于凭空编造预算。 把它设得低于你每次提问的收费(X402_PRICE):等于或高于该值时,每一笔你转包出去的活都赚不到钱,还要自付 gas——而这恰恰惩罚了你希望它做的事,因为它越善于识别自己不懂的部分,就越经常白干。取你价格的三分之一是个合理的起点。 光有数字还不够:还需要 agent.ts 里的 SUBCONTRATA_SKILLS 列表,它规定了可以买什么。默认为空,也就永远不会转包;因为市场搜索在找不到人时会自动泛化,一个请求 \"python video encoding\" 的代码代理最后会搜索 \"video\",把钱付给做视频的代理。",
308
308
  vigilante: "守望者。每 60 秒检查一次你未完成的任务,并挽回卡住的部分:没有上链的交付、中途死掉的工作,或已付款却从未送达的委托。\nVIGILANTE=off 可关闭。PUBLIC_URL 是你的 https 端点,用于丢失委托的提醒。",
309
309
  retirada: "自动提取。托管合约会把每个已批准的委托记在合约里,在有人调用 withdraw 之前不会付款。这个代理每 60 分钟收取一次:当 Gas 不超过提取金额的 2 % 时提取 MON,$PANAL 从 1000 起提取。需要少量 MON 支付 Gas,委托进行中时不会运行。\nRETIRADA=off 可关闭。",
@@ -408,7 +408,7 @@ const hi = {
408
408
  model: 'आपका मॉडल, अगर एजेंट किसी का उपयोग करता है। नाम से प्रदाता चुनें और नीचे उसकी कुंजी डालें।\nLLM_MODEL सुझाए गए मॉडल पर भारी पड़ता है; सूची से बाहर के किसी भी प्रदाता के लिए LLM_BASE_URL है।\nक्लाइंट द्वारा भेजी गई छवियाँ पढ़ने के लिए मॉडल मल्टीमॉडल होना चाहिए।',
409
409
  rpc: 'अपना RPC, अगर सार्वजनिक कम पड़े (इसकी सीमा ~15 कॉल/सेकंड है)।',
410
410
  data: 'दिए गए परिणाम कहाँ सहेजें।',
411
- x402: 'प्रति कॉल शुल्क (वैकल्पिक)। खाली छोड़ें तो आपका एजेंट केवल एस्क्रो वाले काम लेगा।\nकीमत प्रति अनुरोध है, EIP-2612 टोकन में — MON नहीं चल सकता, इस योजना को `permit` चाहिए।',
411
+ x402: 'प्रति कॉल शुल्क (वैकल्पिक)। खाली छोड़ें तो आपका एजेंट केवल एस्क्रो वाले काम लेगा।\nकीमत प्रति अनुरोध है और X402_TOKEN की मुद्रा में पढ़ी जाती है: PANAL (डिफ़ॉल्ट), MON, GHO, USDC या AUSD। USDC के साथ X402_PRICE=0.05 यानी पाँच सेंट। GHO वह स्टेबल है जिसे कोई फ़्रीज़ नहीं कर सकता; USDC और AUSD को उनके जारीकर्ता फ़्रीज़ कर सकते हैं। MON में ग्राहक हस्ताक्षर के बजाय एक छोटा ट्रांसफ़र भेजता है और गैस खुद देता है।',
412
412
  subcontrata: "सबकॉन्ट्रैक्टिंग (वैकल्पिक, डिफ़ॉल्ट रूप से बंद)। आपका एजेंट जो खुद नहीं कर सकता, उसके लिए दूसरे को भुगतान कर सकता है (agent.ts में ctx.consultar देखें)। यहाँ संख्या के बिना वह कभी नहीं सौंपता।\nयह x402 की मुद्रा में है, प्रति कार्य आय का हिस्सा नहीं: कार्य MON में और प्रश्न $PANAL में चुकाया जाता है। इसे अपने प्रति-प्रश्न शुल्क (X402_PRICE) से कम रखें: बराबर या अधिक होने पर, जिस भी काम में आप दूसरे को सौंपेंगे उसमें कुछ नहीं बचेगा और गैस भी आपकी जेब से जाएगी — और यह ठीक उसी व्यवहार को दंडित करता है जो आप चाहते हैं, क्योंकि आपका एजेंट जितना बेहतर पहचानेगा कि उसे क्या नहीं आता, उतनी ही बार वह मुफ़्त काम करेगा। अपने दाम का एक तिहाई एक समझदार शुरुआत है। सिर्फ़ संख्या काफ़ी नहीं: agent.ts में SUBCONTRATA_SKILLS सूची भी चाहिए, जो बताती है कि वह क्या खरीद सकता है। खाली — जैसा यह आता है — तो वह कभी नहीं सौंपता, क्योंकि कोई न मिलने पर बाज़ार की खोज सामान्यीकरण कर देती है, और \"python video encoding\" माँगने वाला कोड एजेंट अंत में \"video\" खोजकर वीडियो बनाने वाले को भुगतान कर देगा।",
413
413
  vigilante: "प्रहरी। हर 60 सेकंड में आपके खुले कार्यों की जाँच करता है और जो अटक गया उसे वापस लाता है: वह डिलीवरी जो चेन पर दर्ज नहीं हुई, अधूरा रह गया काम, या भुगतान किया गया आदेश जो कभी नहीं पहुँचा।\nVIGILANTE=off इसे बंद करता है। PUBLIC_URL आपका https एंडपॉइंट है।",
414
414
  retirada: "स्वचालित निकासी। एस्क्रो हर स्वीकृत आदेश को कॉन्ट्रैक्ट के अंदर जमा करता है और जब तक कोई withdraw न बुलाए, कुछ नहीं भेजता। यह एजेंट हर 60 मिनट में इसे निकालता है: MON तब, जब गैस निकाली गई राशि के 2 % से अधिक न हो, और $PANAL 1000 से। गैस के लिए थोड़ा MON चाहिए, और कोई आदेश चलते समय यह कभी नहीं चलता।\nRETIRADA=off इसे बंद करता है।",
@@ -517,7 +517,7 @@ const ar = {
517
517
  model: 'نموذجك، إن كان وكيلك يستخدم واحدًا. اختر المزوّد بالاسم وضع مفتاحه أدناه.\nمتغيّر LLM_MODEL يتقدّم على النموذج المقترح، و LLM_BASE_URL لأي مزوّد ليس في القائمة.\nلقراءة الصور التي يرفقها العميل، يجب أن يكون النموذج متعدّد الوسائط.',
518
518
  rpc: 'عقدة RPC خاصة بك، إن لم تكفِ العامة (حدّها نحو 15 طلبًا في الثانية).',
519
519
  data: 'مكان حفظ النتائج المُسلَّمة.',
520
- x402: 'التحصيل لكل استدعاء (اختياري). اتركه فارغًا فيقبل وكيلك مهام الضمان فقط.\nالسعر لكل طلب، بعملة تدعم EIP-2612 — لا يصلح MON، فالمخطط يحتاج `permit`.',
520
+ x402: 'التحصيل لكل استدعاء (اختياري). اتركه فارغًا فيقبل وكيلك مهام الضمان فقط.\nالسعر لكل طلب ويُقرأ بعملة X402_TOKEN: ‏PANAL (افتراضيًا) أو MON أو GHO أو USDC أو AUSD. ‏X402_PRICE=0.05 مع USDC تعني خمسة سنتات. ‏GHO هي العملة المستقرة التي لا يستطيع أحد تجميدها؛ أما USDC وAUSD فيمكن لمُصدريهما تجميدهما. مع MON يرسل العميل تحويلًا صغيرًا بدل التوقيع ويدفع رسوم الغاز بنفسه.',
521
521
  subcontrata: "التعاقد من الباطن (اختياري، معطل افتراضيا). يمكن لوكيلك ان يدفع لوكيل اخر مقابل ما لا يجيده (انظر ctx.consultar في agent.ts). بدون رقم هنا لن يفوض ابدا.\nيكون بعملة x402، وليس نسبة مما تتقاضاه عن المهمة: المهمة تدفع بـ MON والسؤال بـ $PANAL. اجعله أقل من سعر السؤال لديك (X402_PRICE): فعند التساوي أو الزيادة، كل مهمة تُسنِد فيها جزءًا إلى غيرك لا تُبقي لك شيئًا وتدفع الغاز من جيبك — وهذا يعاقب تحديدًا ما تريده منه، لأنه كلما أحسن إدراك ما يجهله عمل مجانًا أكثر. ثلث سعرك بداية معقولة. الرقم وحده لا يكفي: تحتاج أيضًا إلى قائمة SUBCONTRATA_SKILLS في agent.ts، التي تحدد ما الذي يُسمح بشرائه. وهي فارغة كما تأتي، فلا يفوّض أبدًا؛ لأن بحث السوق يعمّم عندما لا يجد أحدًا، فوكيل برمجة يطلب \"python video encoding\" ينتهي به الأمر باحثًا عن \"video\" ودافعًا لوكيل يصنع الفيديو.",
522
522
  vigilante: "الحارس. كل 60 ثانية يراجع مهامك المفتوحة ويستعيد ما تعطل: تسليم لم يثبت على السلسلة، او عمل مات في منتصفه، او طلب مدفوع لم يصل قط.\nVIGILANTE=off يوقفه. PUBLIC_URL هو نقطة الوصول https لديك.",
523
523
  retirada: "السحب التلقائي. يقيد الضمان كل طلب معتمد داخل العقد ولا يدفع شيئا حتى يستدعي احد withdraw. يجمعه هذا الوكيل كل 60 دقيقة: MON عندما لا يتجاوز الغاز 2 % من المبلغ، و$PANAL ابتداء من 1000. يحتاج قليلا من MON للغاز، ولا يعمل ابدا اثناء تنفيذ طلب.\nRETIRADA=off يوقفه.",
@@ -625,7 +625,7 @@ La langue vient de --lang, puis de PANAL_LANG, puis de la locale du système.`,
625
625
  model: 'Votre modèle, si votre agent en utilise un. Choisissez un fournisseur par son nom et mettez sa clé ci-dessous.\nLLM_MODEL prime sur le modèle suggéré ; LLM_BASE_URL sert pour tout fournisseur absent de la liste.\nPour lire les images jointes par un client, le modèle doit être multimodal.',
626
626
  rpc: 'Votre propre RPC, si le public ne suffit pas (limité à ~15 appels/s).',
627
627
  data: 'Où stocker les résultats livrés.',
628
- x402: "Facturation à l'appel (facultatif). Laissez vide et votre agent ne prend que des missions sous entiercement.\nLe prix est par requête, dans un jeton EIP-2612 : pas de MON, le schéma exige `permit`.",
628
+ x402: "Facturation à l'appel (facultatif). Laissez vide et votre agent ne prend que des missions sous entiercement.\nLe prix est par requête et se lit dans la monnaie de X402_TOKEN : PANAL (par défaut), MON, GHO, USDC ou AUSD. X402_PRICE=0.05 en USDC, ce sont cinq centimes. GHO est le stable que personne ne peut geler ; USDC et AUSD peuvent être gelés par leurs émetteurs. Avec MON, le client envoie un petit transfert au lieu de signer et paie son propre gas.",
629
629
  subcontrata: "Sous-traitance (optionnelle, desactivee par defaut). Votre agent peut payer un autre pour ce qu il ne sait pas faire (voir ctx.consultar dans agent.ts). Sans un nombre ici, il ne delegue jamais.\nC est dans la devise x402, PAS une part de ce que vous facturez par tache : une tache se paie en MON et une question en $PANAL. Mettez-le EN DESSOUS de ce que vous facturez par question (X402_PRICE) : à égalité ou au-dessus, chaque travail où vous déléguez ne vous laisse rien et vous payez encore le gaz — et cela pénalise précisément ce que vous attendez de lui, car mieux il reconnaît ce qu'il ignore, plus souvent il travaille gratuitement. Un tiers de votre prix est un bon départ. Le nombre ne suffit pas : il faut aussi la liste SUBCONTRATA_SKILLS dans agent.ts, qui dit CE QU'il peut acheter. Vide — comme elle arrive — il ne délègue jamais, car la recherche du marché généralise quand elle ne trouve personne, et un agent de code demandant \"python video encoding\" finirait par chercher \"video\" et payer un agent qui fait des vidéos.",
630
630
  vigilante: "La sentinelle. Toutes les 60 s, elle passe en revue vos taches ouvertes et recupere ce qui est reste bloque : une livraison jamais ancree, un travail mort a mi-chemin, ou une commande payee qui n est jamais arrivee.\nVIGILANTE=off la desactive. PUBLIC_URL est votre endpoint https.",
631
631
  retirada: "Retrait automatique. L escrow credite chaque commande approuvee dans le contrat et ne verse rien tant que personne n appelle withdraw. Toutes les 60 min, cet agent le recupere : le MON quand le gas ne depasse pas 2 % du montant, le $PANAL a partir de 1000. Il faut un peu de MON pour le gas, et il ne tourne jamais pendant une commande en cours.\nRETIRADA=off le desactive.",
@@ -737,7 +737,7 @@ O idioma vem de --lang, depois de PANAL_LANG e, por fim, do locale do sistema.`,
737
737
  model: 'O seu modelo, se o agente usar um. Escolha um fornecedor pelo nome e ponha a sua chave abaixo.\nLLM_MODEL manda sobre o sugerido; LLM_BASE_URL serve para qualquer fornecedor fora da lista.\nPara ler as imagens que um cliente anexe, o modelo tem de ser multimodal.',
738
738
  rpc: 'RPC próprio, se o público não chegar (limita a ~15 chamadas/s).',
739
739
  data: 'Onde guardar os resultados entregues.',
740
- x402: 'Cobrança por chamada (opcional). Deixe vazio e o seu agente só aceita trabalhos do escrow.\nO preço é por pedido, num token EIP-2612: não pode ser MON, o esquema precisa de `permit`.',
740
+ x402: 'Cobrança por chamada (opcional). Deixe vazio e o seu agente só aceita trabalhos do escrow.\nO preço é por pedido e lê-se na moeda de X402_TOKEN: PANAL (por defeito), MON, GHO, USDC ou AUSD. X402_PRICE=0.05 com USDC são cinco cêntimos. GHO é a estável que ninguém pode congelar; USDC e AUSD podem ser congeladas pelos seus emissores. Com MON, o cliente envia uma pequena transferência em vez de assinar e paga o seu próprio gás.',
741
741
  subcontrata: "Subcontratar (opcional, desligado por omissao). O seu agente pode pagar a outro pelo que nao sabe fazer (ver ctx.consultar em agent.ts). Sem um numero aqui, nunca delega.\nVai na moeda do x402 e NAO e uma fatia do que cobra por tarefa: uma tarefa paga-se em MON e uma pergunta em $PANAL. Põe-no ABAIXO do que cobras por pergunta (X402_PRICE): igual ou acima, cada trabalho em que delegues não te deixa nada e ainda pagas o gás — e isso penaliza exactamente o que queres que ele faça, porque quanto melhor reconhecer o que não sabe, mais vezes trabalha de graça. Um terço do teu preço é um começo sensato. O número não chega: é preciso também a lista SUBCONTRATA_SKILLS em agent.ts, que diz O QUE pode comprar. Vazia — como vem — nunca delega, porque a busca do mercado generaliza quando não encontra ninguém, e um agente de código que peça \"python video encoding\" acabaria a procurar \"video\" e a pagar a um que faz vídeos.",
742
742
  vigilante: "O vigia. A cada 60 s reve as suas tarefas abertas e recupera o que ficou preso: uma entrega que nunca foi ancorada, trabalho que morreu a meio, ou uma encomenda paga que nunca chegou.\nVIGILANTE=off desliga-o. PUBLIC_URL e o seu endpoint https.",
743
743
  retirada: "Levantamento automatico. O escrow credita cada encomenda aprovada dentro do contrato e nao paga nada ate alguem chamar withdraw. A cada 60 min este agente recolhe-o: o MON quando o gas nao passa de 2 % do montante, o $PANAL a partir de 1000. Precisa de um pouco de MON para o gas e nunca corre com uma encomenda em curso.\nRETIRADA=off desliga-o.",
@@ -847,7 +847,7 @@ const ru = {
847
847
  model: 'Ваша модель, если агент её использует. Выберите провайдера по имени и укажите его ключ ниже.\nLLM_MODEL важнее предложенной модели; LLM_BASE_URL — для любого провайдера не из списка.\nЧтобы читать изображения, приложенные клиентом, модель должна быть мультимодальной.',
848
848
  rpc: 'Свой RPC, если публичного не хватает (лимит ~15 запросов/с).',
849
849
  data: 'Где хранить сданные результаты.',
850
- x402: 'Плата за вызов (необязательно). Оставьте пустым — агент будет брать только заказы через эскроу.\nЦена за один запрос, в токене с EIP-2612: MON не подходит, схеме нужен `permit`.',
850
+ x402: 'Плата за вызов (необязательно). Оставьте пустым — агент будет брать только заказы через эскроу.\nЦена за один запрос и читается в монете X402_TOKEN: PANAL (по умолчанию), MON, GHO, USDC или AUSD. X402_PRICE=0.05 в USDC — это пять центов. GHO — стейблкоин, который никто не может заморозить; USDC и AUSD могут заморозить их эмитенты. С MON клиент вместо подписи отправляет небольшой перевод и сам платит за газ.',
851
851
  subcontrata: "Субподряд (необязательно, по умолчанию выключен). Ваш агент может заплатить другому за то, чего не умеет сам (см. ctx.consultar в agent.ts). Без числа здесь он никогда не делегирует.\nУказывается в валюте x402, а НЕ долей от оплаты за задачу: задача оплачивается в MON, а вопрос в $PANAL. Поставьте НИЖЕ того, что берёте за вопрос (X402_PRICE): при равенстве или выше каждая работа, где вы делегируете, не приносит ничего, а газ вы платите сами — и это наказывает ровно то поведение, которого вы добиваетесь: чем лучше агент понимает, чего не знает, тем чаще работает даром. Треть вашей цены — разумное начало. Одного числа мало: нужен ещё список SUBCONTRATA_SKILLS в agent.ts, который говорит, ЧТО можно покупать. Пустой — а таким он и поставляется — и агент никогда не делегирует, потому что поиск по рынку обобщает запрос, если никого не нашёл: агент по коду, попросивший \"python video encoding\", в итоге станет искать \"video\" и заплатит тому, кто делает видео.",
852
852
  vigilante: "Сторож. Каждые 60 с проверяет ваши открытые задачи и вытаскивает то, что застряло: доставку, которая не попала в блокчейн, работу, оборвавшуюся на середине, или оплаченный заказ, который так и не пришел.\nVIGILANTE=off выключает его. PUBLIC_URL ваш https-эндпоинт.",
853
853
  retirada: "Автоматический вывод. Эскроу зачисляет каждый одобренный заказ внутри контракта и ничего не отправляет, пока кто-то не вызовет withdraw. Каждые 60 мин этот агент забирает средства: MON, когда газ не больше 2 % от суммы, $PANAL от 1000. Нужно немного MON на газ, и вывод никогда не запускается во время выполнения заказа.\nRETIRADA=off выключает его.",
@@ -958,7 +958,7 @@ const bn = {
958
958
  model: 'আপনার মডেল, যদি এজেন্ট ব্যবহার করে। নাম দিয়ে প্রদানকারী বেছে নিন এবং নিচে তার কী দিন।\nLLM_MODEL প্রস্তাবিত মডেলের উপরে প্রাধান্য পায়; তালিকার বাইরের যেকোনো প্রদানকারীর জন্য LLM_BASE_URL।\nক্লায়েন্টের পাঠানো ছবি পড়তে হলে মডেলটিকে মাল্টিমোডাল হতে হবে।',
959
959
  rpc: 'নিজস্ব RPC, যদি সর্বজনীনটি যথেষ্ট না হয় (সীমা প্রায় ১৫ কল/সেকেন্ড)।',
960
960
  data: 'সরবরাহ করা ফলাফল কোথায় রাখা হবে।',
961
- x402: 'প্রতি কলে চার্জ (ঐচ্ছিক)। ফাঁকা রাখলে আপনার এজেন্ট কেবল এসক্রো কাজ নেবে।\nদাম প্রতি অনুরোধে, EIP-2612 টোকেনে — MON চলবে না, স্কিমটির `permit` দরকার।',
961
+ x402: 'প্রতি কলে চার্জ (ঐচ্ছিক)। ফাঁকা রাখলে আপনার এজেন্ট কেবল এসক্রো কাজ নেবে।\nদাম প্রতি অনুরোধে, আর তা X402_TOKEN-এর মুদ্রায় পড়া হয়: PANAL (ডিফল্ট), MON, GHO, USDC বা AUSD। USDC-তে X402_PRICE=0.05 মানে পাঁচ সেন্ট। GHO হলো সেই স্টেবল যা কেউ ফ্রিজ করতে পারে না; USDC ও AUSD তাদের ইস্যুকারী ফ্রিজ করতে পারে। MON-এ গ্রাহক সই করার বদলে একটি ছোট ট্রান্সফার পাঠায় এবং নিজেই গ্যাস দেয়।',
962
962
  subcontrata: "সাবকন্ট্রাক্টিং (ঐচ্ছিক, ডিফল্টে বন্ধ)। আপনার এজেন্ট যা নিজে পারে না, তার জন্য অন্যকে অর্থ দিতে পারে (agent.ts-এ ctx.consultar দেখুন)। এখানে সংখ্যা না থাকলে সে কখনও দায়িত্ব দেয় না।\nএটি x402-এর মুদ্রায়, কাজপ্রতি আয়ের অংশ নয়: কাজের দাম MON-এ আর প্রশ্নের দাম $PANAL-এ। এটি আপনার প্রতি-প্রশ্ন মূল্যের (X402_PRICE) চেয়ে কম রাখুন: সমান বা বেশি হলে, যে কাজেই আপনি অন্যকে দেবেন তাতে কিছুই থাকবে না, গ্যাসও আপনার — আর এতে ঠিক সেই আচরণই শাস্তি পায় যা আপনি চান, কারণ এজেন্ট যত ভালোভাবে বুঝবে সে কী জানে না, তত বেশিবার সে বিনামূল্যে কাজ করবে। আপনার দামের এক-তৃতীয়াংশ একটি যুক্তিসঙ্গত শুরু। শুধু সংখ্যাই যথেষ্ট নয়: agent.ts-এ SUBCONTRATA_SKILLS তালিকাও লাগে, যা বলে দেয় সে কী কিনতে পারবে। খালি — যেমনটা আসে — হলে সে কখনও দায়িত্ব দেয় না, কারণ কাউকে না পেলে বাজারের খোঁজ সাধারণীকরণ করে, আর \"python video encoding\" চাওয়া কোড এজেন্ট শেষে \"video\" খুঁজে ভিডিও বানায় এমন কাউকে টাকা দিয়ে বসবে।",
963
963
  vigilante: "প্রহরী। প্রতি ৬০ সেকেন্ডে আপনার খোলা কাজগুলি দেখে এবং আটকে যাওয়া জিনিস উদ্ধার করে: চেইনে না ওঠা ডেলিভারি, মাঝপথে মরে যাওয়া কাজ, বা টাকা দেওয়া হয়েছে অথচ কখনও পৌঁছায়নি এমন আদেশ।\nVIGILANTE=off এটি বন্ধ করে। PUBLIC_URL আপনার https এন্ডপয়েন্ট।",
964
964
  retirada: "স্বয়ংক্রিয় উত্তোলন। এসক্রো প্রতিটি অনুমোদিত আদেশ চুক্তির ভিতরে জমা রাখে এবং কেউ withdraw না ডাকা পর্যন্ত কিছু পাঠায় না। এই এজেন্ট প্রতি ৬০ মিনিটে তা তোলে: MON, যখন গ্যাস তোলা অঙ্কের ২ % এর বেশি নয়, আর $PANAL ১০০০ থেকে। গ্যাসের জন্য সামান্য MON লাগে, এবং কোনো আদেশ চলার সময় এটি কখনও চলে না।\nRETIRADA=off এটি বন্ধ করে।",
@@ -1066,7 +1066,7 @@ const ur = {
1066
1066
  model: 'آپ کا ماڈل، اگر ایجنٹ استعمال کرے۔ نام سے فراہم کنندہ چنیں اور نیچے اس کی کلید ڈالیں۔\nLLM_MODEL تجویز کردہ ماڈل پر مقدم ہے؛ فہرست سے باہر کسی بھی فراہم کنندہ کے لیے LLM_BASE_URL ہے۔\nکلائنٹ کی بھیجی ہوئی تصاویر پڑھنے کے لیے ماڈل کا ملٹی موڈل ہونا ضروری ہے۔',
1067
1067
  rpc: 'اپنا RPC، اگر عوامی کم پڑ جائے (حد تقریباً 15 کالز فی سیکنڈ)۔',
1068
1068
  data: 'فراہم کردہ نتائج کہاں محفوظ ہوں۔',
1069
- x402: 'فی کال وصولی (اختیاری)۔ خالی چھوڑ دیں تو آپ کا ایجنٹ صرف ایسکرو کے کام لے گا۔\nقیمت فی درخواست ہے، EIP-2612 ٹوکن میں — MON نہیں چل سکتا، اس اسکیم کو `permit` چاہیے۔',
1069
+ x402: 'فی کال وصولی (اختیاری)۔ خالی چھوڑ دیں تو آپ کا ایجنٹ صرف ایسکرو کے کام لے گا۔\nقیمت فی درخواست ہے اور X402_TOKEN کی کرنسی میں پڑھی جاتی ہے: PANAL (ڈیفالٹ)، MON، GHO، USDC یا AUSD۔ USDC کے ساتھ X402_PRICE=0.05 یعنی پانچ سینٹ۔ GHO وہ اسٹیبل ہے جسے کوئی منجمد نہیں کر سکتا؛ USDC اور AUSD کو ان کے جاری کنندہ منجمد کر سکتے ہیں۔ MON میں کلائنٹ دستخط کے بجائے ایک چھوٹی منتقلی بھیجتا ہے اور گیس خود دیتا ہے۔',
1070
1070
  subcontrata: "سب کنٹریکٹنگ (اختیاری، بذریعہ ڈیفالٹ بند)۔ آپ کا ایجنٹ جو خود نہیں کر سکتا اس کے لیے دوسرے کو ادائیگی کر سکتا ہے (agent.ts میں ctx.consultar دیکھیں)۔ یہاں نمبر کے بغیر وہ کبھی نہیں سونپتا۔\nیہ x402 کی کرنسی میں ہے، فی ٹاسک آمدنی کا حصہ نہیں: ٹاسک MON میں اور سوال $PANAL میں ادا ہوتا ہے۔ اسے اپنی فی سوال قیمت (X402_PRICE) سے کم رکھیں: برابر یا زیادہ ہونے پر، جس کام میں بھی آپ کسی اور کو دیں گے اس میں کچھ نہیں بچے گا اور گیس بھی آپ کی جیب سے جائے گی — اور یہ بالکل اسی رویّے کو سزا دیتا ہے جو آپ چاہتے ہیں، کیونکہ آپ کا ایجنٹ جتنا بہتر پہچانے گا کہ اسے کیا نہیں آتا، اتنی ہی زیادہ بار وہ مفت کام کرے گا۔ اپنی قیمت کا ایک تہائی معقول آغاز ہے۔ صرف عدد کافی نہیں: agent.ts میں SUBCONTRATA_SKILLS کی فہرست بھی چاہیے، جو بتاتی ہے کہ وہ کیا خرید سکتا ہے۔ خالی — جیسا کہ یہ آتا ہے — تو وہ کبھی کام نہیں سونپتا، کیونکہ کوئی نہ ملنے پر مارکیٹ کی تلاش عام کر دیتی ہے، اور \"python video encoding\" مانگنے والا کوڈ ایجنٹ آخر میں \"video\" ڈھونڈ کر ویڈیو بنانے والے کو ادائیگی کر بیٹھے گا۔",
1071
1071
  vigilante: "نگہبان۔ ہر 60 سیکنڈ میں آپ کے کھلے کام دیکھتا ہے اور جو اٹکا ہے اسے بچاتا ہے: وہ ڈیلیوری جو چین پر درج نہ ہوئی، وہ کام جو بیچ میں مر گیا، یا ادا شدہ آرڈر جو کبھی نہ پہنچا۔\nVIGILANTE=off اسے بند کرتا ہے۔ PUBLIC_URL آپ کا https اینڈ پوائنٹ ہے۔",
1072
1072
  retirada: "خودکار نکلوائی۔ ایسکرو ہر منظور شدہ آرڈر کو کنٹریکٹ کے اندر جمع کرتا ہے اور جب تک کوئی withdraw نہ بلائے کچھ نہیں بھیجتا۔ یہ ایجنٹ ہر 60 منٹ میں اسے نکالتا ہے: MON جب گیس نکالی گئی رقم کے 2 % سے زیادہ نہ ہو، اور $PANAL 1000 سے۔ گیس کے لیے تھوڑا MON چاہیے، اور کسی آرڈر کے دوران یہ کبھی نہیں چلتا۔\nRETIRADA=off اسے بند کرتا ہے۔",
package/dist/index.js CHANGED
@@ -257,8 +257,7 @@ function writeEnvExample(dest, t) {
257
257
  '',
258
258
  bloque(t.env.x402),
259
259
  'X402_PRICE=',
260
- '# X402_TOKEN=0x2e2e44e7fa6178822d4397299f719e89d1a67777',
261
- '# X402_SYMBOL=$PANAL',
260
+ '# X402_TOKEN=PANAL',
262
261
  '# X402_DESCRIPTION=',
263
262
  '',
264
263
  bloque(t.env.subcontrata),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-panal-agent",
3
- "version": "0.20.1",
3
+ "version": "0.21.1",
4
4
  "description": "Crea un agente de IA para Panal, funcionando y cobrando on-chain, en cinco minutos",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -30,11 +30,10 @@
30
30
  "node": ">=20"
31
31
  },
32
32
  "devDependencies": {
33
- "@types/node": "^22.0.0",
33
+ "@types/node": "^26.6.4",
34
34
  "tsx": "^4.19.0",
35
35
  "typescript": "^5.6.0",
36
- "unpdf": "^1.8.1",
37
- "xlsx": "^0.18.5"
36
+ "unpdf": "^1.8.1"
38
37
  },
39
38
  "dependencies": {
40
39
  "viem": "^2.21.0"
@@ -10,7 +10,7 @@
10
10
  "typecheck": "tsc --noEmit"
11
11
  },
12
12
  "dependencies": {
13
- "@panal/sdk": "^0.18.0",
13
+ "@panal/sdk": "^0.19.0",
14
14
  "unpdf": "^1.8.1",
15
15
  "dotenv": "^17.0.0",
16
16
  "tsx": "^4.19.0",
@@ -18,6 +18,6 @@
18
18
  },
19
19
  "devDependencies": {
20
20
  "typescript": "^5.6.0",
21
- "@types/node": "^22.0.0"
21
+ "@types/node": "^26.6.4"
22
22
  }
23
23
  }
@@ -410,7 +410,11 @@ async function reclamaTuNombre(account: ReturnType<typeof privateKeyToAccount>,
410
410
  return;
411
411
  }
412
412
 
413
- const hash = await cartera.writeContract({ address: donde, abi: NOMBRES_ABI, functionName: 'reclamar', args: [handle], chain });
413
+ // Con el gas fijado: Monad cobra el límite entero, y viem lo rellena con
414
+ // `eth_fillTransaction`, que el nodo a veces infla.
415
+ const reclamo = { address: donde, abi: NOMBRES_ABI, functionName: 'reclamar', args: [handle], account } as const;
416
+ const estimado = await publico.estimateContractGas(reclamo);
417
+ const hash = await cartera.writeContract({ ...reclamo, gas: (estimado * 11n + 9n) / 10n, chain });
414
418
  await publico.waitForTransactionReceipt({ hash });
415
419
  console.log(`\nTu nombre único en Panal: ${handle}`);
416
420
  } catch (err) {
@@ -42,7 +42,6 @@ import {
42
42
  nivelPara,
43
43
  parseAttachmentsManifest,
44
44
  parseEnvelope,
45
- parsePaymentHeader,
46
45
  permitNonce,
47
46
  readPermitDomain,
48
47
  sanitizeFileName,
@@ -55,10 +54,21 @@ import {
55
54
  type LlmConfig,
56
55
  type Nivel,
57
56
  type PermitDomain,
57
+ type X402Currency,
58
+ X402_NATIVE_SCHEME,
59
+ buildNativeQuote,
60
+ formatX402Amount,
61
+ newQuoteSecret,
62
+ parseX402Header,
63
+ parseX402Amount,
64
+ resourceId,
65
+ verifyNativePayment,
66
+ x402Currencies,
67
+ x402CurrencyByName,
58
68
  } from '@panal/sdk';
59
69
  import { comoAdjunto } from './salida.js';
60
70
  import { privateKeyToAccount } from 'viem/accounts';
61
- import { isAddress, keccak256, parseEther, toBytes, verifyMessage } from 'viem';
71
+ import { isAddress, keccak256, parseEther, parseUnits, toBytes, verifyMessage } from 'viem';
62
72
  import type { Address } from 'viem';
63
73
  import { handleTask, NIVELES, SUBCONTRATA_SKILLS } from './agent.js';
64
74
  import { frasesGuardadas, pedirTraduccion } from './traduccion.js';
@@ -303,26 +313,57 @@ setInterval(() => void refrescarNiveles(), REFRESCO_NIVELES).unref();
303
313
  // Es OPCIONAL: sin X402_PRICE en el .env, esta ruta no existe y tu agente
304
314
  // funciona igual solo con encargos del escrow.
305
315
  //
306
- // Solo se puede cobrar en un ERC-20 con EIP-2612, no en MON: el esquema entero
307
- // se apoya en `permit`, y la moneda nativa no lo tiene.
316
+ // Se cobra en una de las monedas que Panal acepta: $PANAL (por defecto), MON,
317
+ // GHO, USDC o AUSD. Las de token tienen `permit`: el cliente firma y tú
318
+ // ejecutas el cobro. MON no lo tiene: el cliente te MANDA la transferencia
319
+ // (paga él su gas) y tú solo compruebas en la cadena que es la de su
320
+ // cotización. El nombre y los decimales salen de la lista del SDK
321
+ // (`x402Currencies`), no de lo que se escriba aquí: así el precio que ves en
322
+ // el .env es el que ven los clientes.
323
+ //
324
+ // X402_TOKEN=USDC
325
+ // X402_PRICE=0.05 # cinco céntimos: se lee en la moneda elegida
308
326
  // ---------------------------------------------------------------------------
309
327
 
328
+ const X402_MONEDA: X402Currency | null = (() => {
329
+ const raw = process.env.X402_TOKEN?.trim() || MAINNET_ADDRESSES.panalToken;
330
+ const moneda = x402CurrencyByName(raw);
331
+ if (!moneda) {
332
+ const aceptadas = x402Currencies().map((c) => c.symbol).join(', ');
333
+ console.error(`X402_TOKEN="${raw}" no es una moneda que Panal acepte (${aceptadas}): el cobro por llamada queda desactivado.`);
334
+ }
335
+ return moneda;
336
+ })();
310
337
  const X402_PRICE = (() => {
311
338
  const raw = process.env.X402_PRICE?.trim();
312
- if (!raw) return null;
339
+ if (!raw || !X402_MONEDA) return null;
313
340
  try {
314
- const wei = parseEther(raw);
315
- return wei > 0n ? wei : null;
341
+ // En los decimales de SU moneda. Con parseEther, «0.05» en USDC eran
342
+ // 5·10¹⁶ unidades: cincuenta mil millones de dólares por pregunta.
343
+ const unidades = parseX402Amount(raw, X402_MONEDA);
344
+ return unidades > 0n ? unidades : null;
316
345
  } catch {
317
346
  console.error(`X402_PRICE="${raw}" no es un número válido: el cobro por llamada queda desactivado.`);
318
347
  return null;
319
348
  }
320
349
  })();
321
- const X402_TOKEN: Address = (() => {
322
- const raw = process.env.X402_TOKEN?.trim();
323
- return raw && isAddress(raw) ? (raw as Address) : MAINNET_ADDRESSES.panalToken;
324
- })();
325
- const X402_SYMBOL = process.env.X402_SYMBOL?.trim() || '$PANAL';
350
+ // Con la moneda desactivada se quedan los de $PANAL: los usa el log y el
351
+ // presupuesto de subcontratar, que siguen leyéndose aunque no se cobre.
352
+ const X402_TOKEN: Address = X402_MONEDA?.address ?? (MAINNET_ADDRESSES.panalToken as Address);
353
+ const X402_SYMBOL = X402_MONEDA?.symbol ?? '$PANAL';
354
+ const X402_DECIMALES = X402_MONEDA?.decimals ?? 18;
355
+ /** Si se cobra en MON: transferencia del cliente en vez de permit. */
356
+ const X402_EN_MON = X402_MONEDA?.scheme === X402_NATIVE_SCHEME;
357
+ /**
358
+ * Con MON, el secreto con el que se firman las cotizaciones y las
359
+ * transferencias ya cobradas. Basta en memoria: una cotización vale 5 minutos,
360
+ * y al reiniciar se pide otra.
361
+ */
362
+ const X402_SECRETO = newQuoteSecret();
363
+ const X402_USADOS = new Set<string>();
364
+ if (process.env.X402_SYMBOL?.trim() && process.env.X402_SYMBOL.trim() !== X402_SYMBOL) {
365
+ console.warn(`[panal] X402_SYMBOL ya no se usa: el nombre sale de X402_TOKEN, y es ${X402_SYMBOL}.`);
366
+ }
326
367
  // En inglés porque viaja en el 402 y lo lee un desconocido de cualquier parte.
327
368
  // Cámbialo por lo tuyo con X402_DESCRIPTION en el .env.
328
369
  const X402_DESCRIPTION = process.env.X402_DESCRIPTION?.trim() || 'One question to the agent, answered on the spot.';
@@ -352,7 +393,7 @@ const SUBCONTRATA_MAX = (() => {
352
393
  const raw = process.env.SUBCONTRATA_MAX?.trim();
353
394
  if (!raw) return 0n;
354
395
  try {
355
- const wei = parseEther(raw);
396
+ const wei = parseUnits(raw, X402_DECIMALES);
356
397
  return wei > 0n ? wei : 0n;
357
398
  } catch {
358
399
  console.error(`SUBCONTRATA_MAX="${raw}" no es un número válido: tu agente no subcontratará.`);
@@ -762,6 +803,9 @@ function contexto(
762
803
  }
763
804
  const res = await panal.ask(skill, pregunta, {
764
805
  maxSpend: presupuesto,
806
+ // En la moneda del presupuesto, que es la del x402: solo se cotiza con
807
+ // quien cobre en ella.
808
+ asset: X402_TOKEN,
765
809
  skillsPermitidas: SUBCONTRATA_SKILLS,
766
810
  depth: SUBCONTRATA_SALTOS,
767
811
  // El sobre recibido, si lo hay. Sin él se abre una cadena nueva.
@@ -771,7 +815,7 @@ function contexto(
771
815
  exclude: [account.address],
772
816
  });
773
817
  console.log(
774
- `[panal] consulta a ${res.agent} por ${res.paid} (${skill}) · trace ${sobre?.trace ?? 'nuevo'}`,
818
+ `[panal] consulta a ${res.agent} por ${formatX402Amount(res.paid, res.currency)} ${res.currency.symbol} (${skill}) · trace ${sobre?.trace ?? 'nuevo'}`,
775
819
  );
776
820
  return res.answer;
777
821
  },
@@ -1313,12 +1357,17 @@ const server = createServer((req, res) => {
1313
1357
  method: 'POST' as const,
1314
1358
  path: '/x402/ask',
1315
1359
  ...(base ? { url: `${base}/x402/ask` } : {}),
1316
- scheme: 'eip2612-permit',
1360
+ scheme: X402_EN_MON ? X402_NATIVE_SCHEME : 'eip2612-permit',
1317
1361
  asset: X402_TOKEN,
1318
1362
  assetSymbol: X402_SYMBOL,
1363
+ // Para quien lea la ficha a mano. Los clientes de Panal no se
1364
+ // fían de esto: sacan los decimales de su propia lista.
1365
+ assetDecimals: X402_DECIMALES,
1319
1366
  amount: X402_PRICE.toString(),
1320
1367
  payTo: account.address,
1321
- howTo: 'POST {"prompt":"…"} and you get a 402 with the quote. Sign it and repeat with X-Payment.',
1368
+ howTo: X402_EN_MON
1369
+ ? 'POST {"prompt":"…"} and you get a 402 with the quote. Send exactly `amount` MON to `payTo` and repeat with X-Payment.'
1370
+ : 'POST {"prompt":"…"} and you get a 402 with the quote. Sign it and repeat with X-Payment.',
1322
1371
  }
1323
1372
  : null;
1324
1373
 
@@ -1406,7 +1455,9 @@ const server = createServer((req, res) => {
1406
1455
  throw err;
1407
1456
  }
1408
1457
 
1409
- const domain = await dominioPermit();
1458
+ // El pago se ata a ESTA pregunta: una transferencia en MON presentada con
1459
+ // otra pregunta no cuadra.
1460
+ const recurso = resourceId('POST', '/x402/ask', prompt);
1410
1461
  const pagoCrudo = req.headers['x-payment'];
1411
1462
 
1412
1463
  // Sin pago: se responde 402 con el presupuesto. Este es el paso que le da
@@ -1417,6 +1468,23 @@ const server = createServer((req, res) => {
1417
1468
  // consulta a la cadena antes de poder firmar.
1418
1469
  const quien = req.headers['x-payment-payer'];
1419
1470
  const payer = typeof quien === 'string' && isAddress(quien) ? (quien as Address) : null;
1471
+ if (X402_EN_MON) {
1472
+ res.setHeader('www-authenticate', `${X402_NATIVE_SCHEME} realm="panal"`);
1473
+ json(
1474
+ res,
1475
+ 402,
1476
+ buildNativeQuote({
1477
+ secret: X402_SECRETO,
1478
+ price: X402_PRICE,
1479
+ payTo: account.address,
1480
+ resource: recurso,
1481
+ description: X402_DESCRIPTION,
1482
+ payer,
1483
+ }),
1484
+ );
1485
+ return;
1486
+ }
1487
+ const domain = await dominioPermit();
1420
1488
  const nonce = payer ? await permitNonce(panal.publicClient, X402_TOKEN, payer).catch(() => undefined) : undefined;
1421
1489
 
1422
1490
  res.setHeader('www-authenticate', `eip2612-permit realm="panal", chain="${domain.chainId}"`);
@@ -1437,19 +1505,38 @@ const server = createServer((req, res) => {
1437
1505
  return;
1438
1506
  }
1439
1507
 
1440
- const leido = parsePaymentHeader(pagoCrudo);
1508
+ const leido = parseX402Header(pagoCrudo);
1441
1509
  if (!leido.ok) {
1442
1510
  json(res, 400, { error: leido.error });
1443
1511
  return;
1444
1512
  }
1513
+ if ((leido.payment.scheme === X402_NATIVE_SCHEME) !== X402_EN_MON) {
1514
+ json(res, 400, { error: `this agent charges in ${X402_SYMBOL}: ask for a new quote` });
1515
+ return;
1516
+ }
1445
1517
 
1446
1518
  // SE COBRA ANTES DE SERVIR. Si se sirviera primero y el cobro fallara, el
1447
- // trabajo estaría regalado y no habría forma de recuperarlo.
1448
- const cobro = await verifyAndSettle(
1449
- { publicClient: panal.publicClient, walletClient: panal.walletClient ?? null, token: X402_TOKEN, domain, payee: account.address },
1450
- leido.payment,
1451
- X402_PRICE,
1452
- );
1519
+ // trabajo estaría regalado y no habría forma de recuperarlo. En MON el
1520
+ // dinero ya lo mandó el cliente: se comprueba en la cadena que es el de
1521
+ // su cotización y que no se ha usado antes.
1522
+ const cobro =
1523
+ leido.payment.scheme === X402_NATIVE_SCHEME
1524
+ ? await verifyNativePayment(
1525
+ { publicClient: panal.publicClient, payee: account.address, secret: X402_SECRETO, used: X402_USADOS },
1526
+ leido.payment,
1527
+ { price: X402_PRICE, resource: recurso },
1528
+ )
1529
+ : await verifyAndSettle(
1530
+ {
1531
+ publicClient: panal.publicClient,
1532
+ walletClient: panal.walletClient ?? null,
1533
+ token: X402_TOKEN,
1534
+ domain: await dominioPermit(),
1535
+ payee: account.address,
1536
+ },
1537
+ leido.payment,
1538
+ X402_PRICE,
1539
+ );
1453
1540
  if (!cobro.ok) {
1454
1541
  json(res, cobro.status, { error: cobro.error });
1455
1542
  return;