2020117-agent 0.4.2 → 0.4.3

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
@@ -333,6 +333,10 @@ async function publishHandlerInfo(label) {
333
333
  about: state.skill?.description || `DVM agent (kind ${KIND})`,
334
334
  pricing: { [String(KIND)]: SATS_PER_CHUNK * CHUNKS_PER_PAYMENT },
335
335
  };
336
+ if (LIGHTNING_ADDRESS) {
337
+ content.payment = { lightning_address: LIGHTNING_ADDRESS };
338
+ content.lud16 = LIGHTNING_ADDRESS;
339
+ }
336
340
  const event = signEvent({
337
341
  kind: 31990,
338
342
  tags: [
@@ -449,17 +453,43 @@ async function handleDvmRequest(label, event) {
449
453
  console.log(`[${label}] DVM result: ${result.length} chars`);
450
454
  // Send result (Kind 6xxx = request kind + 1000)
451
455
  const resultKind = KIND + 1000;
456
+ const resultTags = [
457
+ ['p', event.pubkey],
458
+ ['e', event.id],
459
+ ['request', JSON.stringify(event)],
460
+ ['amount', String(SATS_PER_CHUNK * CHUNKS_PER_PAYMENT * 1000)], // msats
461
+ ];
462
+ if (LIGHTNING_ADDRESS) {
463
+ resultTags.push(['lightning_address', LIGHTNING_ADDRESS]);
464
+ }
452
465
  const resultEvent = signEvent({
453
466
  kind: resultKind,
454
- tags: [
455
- ['p', event.pubkey],
456
- ['e', event.id],
457
- ['request', JSON.stringify(event)],
458
- ],
467
+ tags: resultTags,
459
468
  content: result,
460
469
  }, state.sovereignKeys.privkey);
461
470
  await state.relayPool.publish(resultEvent);
462
471
  console.log(`[${label}] Published DVM result (Kind ${resultKind}) via relay`);
472
+ // Publish reputation endorsement (Kind 30311) for customer
473
+ try {
474
+ const endorsementEvent = signEvent({
475
+ kind: 30311,
476
+ tags: [
477
+ ['d', event.pubkey],
478
+ ['p', event.pubkey],
479
+ ['rating', '5'],
480
+ ['k', String(KIND)],
481
+ ],
482
+ content: JSON.stringify({
483
+ rating: 5,
484
+ context: { jobs_together: 1, kinds: [KIND], last_job_at: Math.floor(Date.now() / 1000) },
485
+ }),
486
+ }, state.sovereignKeys.privkey);
487
+ await state.relayPool.publish(endorsementEvent);
488
+ console.log(`[${label}] Published endorsement (Kind 30311) for ${event.pubkey.slice(0, 8)}`);
489
+ }
490
+ catch (e) {
491
+ console.warn(`[${label}] Failed to publish endorsement: ${e.message}`);
492
+ }
463
493
  }
464
494
  finally {
465
495
  releaseSlot();
@@ -676,7 +706,14 @@ async function startSwarmListener(label) {
676
706
  node.on('message', async (msg, socket, peerId) => {
677
707
  const tag = peerId.slice(0, 8);
678
708
  if (msg.type === 'skill_request') {
679
- node.send(socket, { type: 'skill_response', id: msg.id, skill: state.skill });
709
+ const satsPerMinute = state.skill?.pricing?.sats_per_minute
710
+ || Number(process.env.SATS_PER_MINUTE)
711
+ || 10;
712
+ // Always include runtime pricing, even without a skill file
713
+ const skillWithPricing = state.skill
714
+ ? { ...state.skill, pricing: { ...(state.skill.pricing || {}), sats_per_minute: satsPerMinute } }
715
+ : { pricing: { sats_per_minute: satsPerMinute }, payment_methods: LIGHTNING_ADDRESS ? ['cashu', 'invoice'] : ['cashu'] };
716
+ node.send(socket, { type: 'skill_response', id: msg.id, skill: skillWithPricing });
680
717
  return;
681
718
  }
682
719
  // --- Session protocol ---
package/dist/session.js CHANGED
@@ -64,6 +64,15 @@ const MINT_URL = process.env.CASHU_MINT_URL || 'https://8333.space:3338';
64
64
  let cashuState = null;
65
65
  const TICK_INTERVAL_MS = 60_000;
66
66
  const HTTP_TIMEOUT_MS = 60_000;
67
+ function confirmPrompt(question) {
68
+ return new Promise(resolve => {
69
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
70
+ rl.question(question, answer => {
71
+ rl.close();
72
+ resolve(answer.trim().toLowerCase() === 'y' || answer.trim().toLowerCase() === 'yes');
73
+ });
74
+ });
75
+ }
67
76
  const state = {
68
77
  node: null,
69
78
  socket: null,
@@ -701,8 +710,26 @@ async function main() {
701
710
  const pricing = skill?.pricing;
702
711
  const satsPerMinute = Number(pricing?.sats_per_minute) || 10;
703
712
  state.satsPerMinute = satsPerMinute;
704
- log(`Pricing: ${satsPerMinute} sats/min`);
705
- log(`Budget: ${BUDGET} sats (~${Math.floor(BUDGET / satsPerMinute)} min)`);
713
+ // Price confirmation
714
+ const minutesAvailable = Math.floor(BUDGET / satsPerMinute);
715
+ log('');
716
+ log('┌─────────────────────────────────');
717
+ log(`│ Rate: ${satsPerMinute} sats/min`);
718
+ log(`│ Budget: ${BUDGET} sats`);
719
+ log(`│ Duration: ~${minutesAvailable} min`);
720
+ if (skill?.payment_methods) {
721
+ log(`│ Payment: ${skill.payment_methods.join(', ')}`);
722
+ }
723
+ log('└─────────────────────────────────');
724
+ log('');
725
+ if (process.stdin.isTTY) {
726
+ const confirmed = await confirmPrompt('Start session? (y/n): ');
727
+ if (!confirmed) {
728
+ log('Session cancelled.');
729
+ await node.destroy();
730
+ process.exit(0);
731
+ }
732
+ }
706
733
  // 4. Determine payment method: Cashu (default) or invoice (fallback)
707
734
  let paymentMethod;
708
735
  if (CASHU_TOKEN) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "2020117-agent",
3
- "version": "0.4.2",
3
+ "version": "0.4.3",
4
4
  "description": "2020117 agent runtime — API polling + Hyperswarm P2P + Sovereign Nostr mode + Cashu/Lightning payments",
5
5
  "type": "module",
6
6
  "bin": {