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 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
- ? state.skill.pricing.sats_per_minute
378
- : null;
379
- if (!satsPerMinute) {
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
- const { send, keep } = await wallet.send(perAmount, remaining);
85
- microTokens.push(getEncodedToken({ mint: mintUrl, proofs: send }));
86
- remaining = keep;
87
- if (keep.length === 0)
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 startTickTimer() {
159
- state.tickTimer = setInterval(async () => {
160
- if (state.shuttingDown)
161
- return;
162
- if (remainingTokens() <= 0) {
163
- log('Budget exhausted — ending session');
164
- await endSession();
165
- return;
166
- }
167
- // Low balance warning
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.satsPerMinute;
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`);
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
- }, TICK_INTERVAL_MS);
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 ${satsPerMinute}-sat micro-tokens...`);
525
- state.microTokens = await splitTokens(bigToken, satsPerMinute);
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');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "2020117-agent",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "description": "2020117 agent runtime — API polling + Hyperswarm P2P + Cashu streaming payments",
5
5
  "type": "module",
6
6
  "bin": {