libaskexperts
Version:
A TypeScript library to create experts based on NIP-174
160 lines (125 loc) • 4.32 kB
Markdown
# libaskexperts - Create Your Own Experts
A TypeScript library to create experts based on [NIP-174](https://github.com/nostrband/askexperts/blob/main/NIP-174.md) (AskExperts) protocol.
AskExperts is intended to be used by MCP tools as clients to find experts and ask them questions in exchange for a Lightning Network payment.
## Overview
This library provides an `Expert` class that encapsulates all the logic of the NIP-174 protocol, handling Nostr events and Lightning payments. It allows you to create your own expert by implementing two callback functions:
- `onAsk`: Called when a new ask is received, returns a bid if the expert wants to participate
- `onQuestion`: Called when a question is received, returns an answer to the question
## Installation
```bash
npm install libaskexperts
```
## Usage
```typescript
import { Expert } from 'libaskexperts';
import { generateSecretKey, getPublicKey } from 'nostr-tools';
import { nwc } from '@getalby/sdk';
// Create a wallet for generating invoices
const nwcClient = new nwc.NWCClient({ nostrWalletConnectUrl: "your-nwc-string" });
// Generate expert keypair
const expertPrivateKey = generateSecretKey();
const expertPublicKey = getPublicKey(expertPrivateKey);
// Create an expert instance
const expert = new Expert({
nwcString,
expertPrivkey: expertPrivateKey,
askRelays: ["wss://relay.nostr.band", "wss://relay.damus.io"],
questionRelays: ["wss://relay.nostr.band", "wss://relay.damus.io"],
hashtags: ["ai", "programming"], // Listen for asks with these hashtags
min_bid_sats: 50, // Ignore asks with max_bid_sats less than 50
onAsk: async (ask) => {
// Evaluate the ask and decide whether to bid
return {
content: "I can help with your programming question!",
bid_sats: 100, // Charge 100 sats for an answer
};
},
onQuestion: async (ask, bid, question, history) => {
// Generate an answer to the question
// history contains previous question-answer pairs for followups
return {
content: "Here's the answer to your question...",
followup_sats: 50, // Allow followup questions for 50 sats
};
},
bidTimeout: 600, // 10 minutes
});
// Start the expert
expert.start();
// To stop the expert and clean up resources
expert[Symbol.dispose]();
```
## API
### Expert Class
```typescript
class Expert {
constructor(params: ExpertParams);
start(): void;
[Symbol.dispose](): void;
}
```
### ExpertParams Interface
```typescript
interface ExpertParams {
nwcString: string;
expertPrivkey: Uint8Array;
askRelays: string[];
questionRelays: string[];
hashtags: string[];
onAsk: (ask: Ask) => Promise<Bid | undefined>;
onQuestion: (ask: Ask, bid: Bid, question: Question, history?: QuestionAnswerPair[]) => Promise<Answer>;
bidTimeout?: number;
min_bid_sats?: number; // Minimum bid amount in satoshis that the expert will accept
}
```
### Ask Interface
```typescript
interface Ask {
id: string;
pubkey: string;
content: string;
created_at: number;
tags: string[][];
hashtags: string[]; // Hashtags parsed from 't' tags
max_bid_sats?: number; // Maximum bid amount in satoshis
}
```
### Bid Interface
```typescript
interface Bid {
content: string;
bid_sats: number;
tags?: string[][];
}
```
### Question Interface
```typescript
interface Question {
id: string;
content: string;
preimage: string;
tags?: string[][];
}
```
### Answer Interface
```typescript
interface Answer {
content: string;
followup_sats?: number; // Amount to charge for followup questions
tags?: string[][];
}
```
### QuestionAnswerPair Interface
```typescript
interface QuestionAnswerPair {
question: Question;
answer: Answer;
}
```
## Followup Questions
The library supports followup questions, allowing clients to ask additional questions after receiving an answer. To enable followup questions:
1. In your `onQuestion` callback, return an `Answer` with the `followup_sats` property set to the amount you want to charge for a followup.
2. The library will automatically generate an invoice and include it in the answer.
3. When a client pays the invoice and asks a followup question, your `onQuestion` callback will be called again with the original ask, bid, the new question, and a history of previous question-answer pairs.
## License
MIT