2020117-agent 0.1.4 → 0.1.6
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.js +4 -7
- package/dist/cashu.js +21 -4
- package/dist/session.js +44 -33
- package/package.json +1 -1
package/dist/agent.js
CHANGED
|
@@ -373,13 +373,10 @@ async function startSwarmListener(label) {
|
|
|
373
373
|
}
|
|
374
374
|
// --- Session protocol ---
|
|
375
375
|
if (msg.type === 'session_start') {
|
|
376
|
-
const satsPerMinute = state.skill?.pricing
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
node.send(socket, { type: 'error', id: msg.id, message: 'Provider does not support sessions (no pricing.sats_per_minute in skill)' });
|
|
381
|
-
return;
|
|
382
|
-
}
|
|
376
|
+
const satsPerMinute = state.skill?.pricing?.sats_per_minute
|
|
377
|
+
|| Number(process.env.SATS_PER_MINUTE)
|
|
378
|
+
|| msg.sats_per_minute
|
|
379
|
+
|| 10;
|
|
383
380
|
const sessionId = randomBytes(8).toString('hex');
|
|
384
381
|
console.log(`[${label}] Session ${sessionId} from ${tag}: ${satsPerMinute} sats/min`);
|
|
385
382
|
const session = {
|
package/dist/cashu.js
CHANGED
|
@@ -81,10 +81,27 @@ export async function splitTokens(tokenStr, perAmount) {
|
|
|
81
81
|
const total = remaining.reduce((sum, p) => sum + p.amount, 0);
|
|
82
82
|
if (total < perAmount)
|
|
83
83
|
break;
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
84
|
+
let retries = 5;
|
|
85
|
+
while (retries > 0) {
|
|
86
|
+
try {
|
|
87
|
+
const { send, keep: kept } = await wallet.send(perAmount, remaining);
|
|
88
|
+
microTokens.push(getEncodedToken({ mint: mintUrl, proofs: send }));
|
|
89
|
+
remaining = kept;
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
92
|
+
catch (e) {
|
|
93
|
+
if (retries > 1 && /rate.limit/i.test(e.message || '')) {
|
|
94
|
+
const delay = (6 - retries) * 2000; // 2s, 4s, 6s, 8s
|
|
95
|
+
console.log(`[cashu] Rate limited, waiting ${delay / 1000}s... (${retries - 1} retries left)`);
|
|
96
|
+
await sleep(delay);
|
|
97
|
+
retries--;
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
throw e;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
if (remaining.length === 0)
|
|
88
105
|
break;
|
|
89
106
|
}
|
|
90
107
|
console.log(`[cashu] Split into ${microTokens.length} micro-tokens of ${perAmount} sats each`);
|
package/dist/session.js
CHANGED
|
@@ -59,6 +59,8 @@ const state = {
|
|
|
59
59
|
sessionId: '',
|
|
60
60
|
skill: null,
|
|
61
61
|
satsPerMinute: 0,
|
|
62
|
+
satsPerToken: 1,
|
|
63
|
+
tickIntervalMs: 60_000,
|
|
62
64
|
microTokens: [],
|
|
63
65
|
tokenIndex: 0,
|
|
64
66
|
totalSpent: 0,
|
|
@@ -155,38 +157,42 @@ function setupMessageHandler() {
|
|
|
155
157
|
});
|
|
156
158
|
}
|
|
157
159
|
// --- 3. Tick timer ---
|
|
158
|
-
function
|
|
159
|
-
state.
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
const
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
}
|
|
182
|
-
if (resp.balance !== undefined) {
|
|
183
|
-
log(`Tick OK — balance: ${resp.balance} sats`);
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
catch (e) {
|
|
187
|
-
warn(`Tick failed: ${e.message}`);
|
|
160
|
+
async function sendTick() {
|
|
161
|
+
if (state.shuttingDown)
|
|
162
|
+
return false;
|
|
163
|
+
if (remainingTokens() <= 0) {
|
|
164
|
+
log('Budget exhausted — ending session');
|
|
165
|
+
await endSession();
|
|
166
|
+
return false;
|
|
167
|
+
}
|
|
168
|
+
if (remainingTokens() <= 2) {
|
|
169
|
+
warn(`Low balance! Only ${remainingTokens()} tick(s) remaining (${remainingSats()} sats)`);
|
|
170
|
+
}
|
|
171
|
+
const token = state.microTokens[state.tokenIndex++];
|
|
172
|
+
state.totalSpent += state.satsPerToken;
|
|
173
|
+
const tickId = randomBytes(4).toString('hex');
|
|
174
|
+
try {
|
|
175
|
+
const resp = await sendAndWait({
|
|
176
|
+
type: 'session_tick',
|
|
177
|
+
id: tickId,
|
|
178
|
+
session_id: state.sessionId,
|
|
179
|
+
token,
|
|
180
|
+
budget: BUDGET,
|
|
181
|
+
}, 15_000);
|
|
182
|
+
if (resp.balance !== undefined) {
|
|
183
|
+
log(`Tick OK — balance: ${resp.balance} sats`);
|
|
188
184
|
}
|
|
189
|
-
|
|
185
|
+
return true;
|
|
186
|
+
}
|
|
187
|
+
catch (e) {
|
|
188
|
+
warn(`Tick failed: ${e.message}`);
|
|
189
|
+
return false;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
function startTickTimer() {
|
|
193
|
+
// Send first tick immediately (prepay) to prevent provider timeout
|
|
194
|
+
sendTick();
|
|
195
|
+
state.tickTimer = setInterval(() => sendTick(), state.tickIntervalMs);
|
|
190
196
|
}
|
|
191
197
|
// --- 4. HTTP proxy ---
|
|
192
198
|
function startHttpProxy() {
|
|
@@ -519,10 +525,15 @@ async function main() {
|
|
|
519
525
|
log(`Pricing: ${satsPerMinute} sats/min`);
|
|
520
526
|
log(`Budget: ${BUDGET} sats (~${Math.floor(BUDGET / satsPerMinute)} min)`);
|
|
521
527
|
// 4. Mint and split tokens
|
|
528
|
+
// Cashu tokens must be whole sats. If rate < 1, use 1 sat tokens with longer tick intervals.
|
|
529
|
+
const satsPerToken = Math.max(1, Math.ceil(satsPerMinute));
|
|
530
|
+
const tickMinutes = satsPerToken / satsPerMinute; // e.g. 0.1 sats/min → 1 sat every 10 min
|
|
531
|
+
state.tickIntervalMs = Math.round(tickMinutes * 60_000);
|
|
532
|
+
state.satsPerToken = satsPerToken;
|
|
522
533
|
log(`Minting ${BUDGET} sats...`);
|
|
523
534
|
const { token: bigToken } = await mintTokens(BUDGET);
|
|
524
|
-
log(`Splitting into ${
|
|
525
|
-
state.microTokens = await splitTokens(bigToken,
|
|
535
|
+
log(`Splitting into ${satsPerToken}-sat micro-tokens (tick every ${tickMinutes} min)...`);
|
|
536
|
+
state.microTokens = await splitTokens(bigToken, satsPerToken);
|
|
526
537
|
log(`Ready: ${state.microTokens.length} micro-tokens`);
|
|
527
538
|
if (state.microTokens.length === 0) {
|
|
528
539
|
warn('Budget too small for even one tick payment');
|