update nip89 params to a table

This commit is contained in:
dbth 2024-11-22 12:31:09 +01:00 committed by GitHub
parent f07d71456f
commit 581e853bcf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

327
90.md
View File

@ -11,41 +11,69 @@ This NIP defines the interaction between customers and Service Providers for per
Money in, data out. Money in, data out.
## Kinds ## Kinds
This NIP reserves the range `5000-7000` for data vending machine use. This NIP reserves the range `5000-7000` for data vending machine use.
| Kind | Description | | Kind | Description |
| ---- | ----------- | |-----------|-------------------|
| 5000-5999 | Job request kinds | | 5000-5999 | Job request kinds |
| 6000-6999 | Job result | | 6000-6999 | Job result |
| 7000 | Job feedback | | 7000 | Job feedback |
Job results always use a kind number that is `1000` higher than the job request kind. (e.g. request: `kind:5001` gets a result: `kind:6001`). Job results always use a kind number that is `1000` higher than the job request kind. (e.g. request: `kind:5001` gets a
result: `kind:6001`).
Job request types are defined [separately](https://github.com/nostr-protocol/data-vending-machines/tree/master/kinds). Job request types are defined [separately](https://github.com/nostr-protocol/data-vending-machines/tree/master/kinds).
## Rationale ## Rationale
Nostr can act as a marketplace for data processing, where users request jobs to be processed in certain ways (e.g., "speech-to-text", "summarization", etc.), but they don't necessarily care about "who" processes the data.
This NIP is not to be confused with a 1:1 marketplace; instead, it describes a flow where a user announces a desired output, willingness to pay, and service providers compete to fulfill the job requirement in the best way possible. Nostr can act as a marketplace for data processing, where users request jobs to be processed in certain ways (e.g., "
speech-to-text", "summarization", etc.), but they don't necessarily care about "who" processes the data.
This NIP is not to be confused with a 1:1 marketplace; instead, it describes a flow where a user announces a desired
output, willingness to pay, and service providers compete to fulfill the job requirement in the best way possible.
### Actors ### Actors
There are two actors in the workflow described in this NIP: There are two actors in the workflow described in this NIP:
* Customers (npubs who request a job) * Customers (npubs who request a job)
* Service providers (npubs who fulfill jobs) * Service providers (npubs who fulfill jobs)
## Job request (`kind:5000-5999`) ## Job request (`kind:5000-5999`)
A request to process data, published by a customer. This event signals that a customer is interested in receiving the result of some kind of compute.
A request to process data, published by a customer. This event signals that a customer is interested in receiving the
result of some kind of compute.
```json ```json
{ {
"kind": 5xxx, // kind in 5000-5999 range "kind": 5xxx,
// kind in 5000-5999 range
"content": "", "content": "",
"tags": [ "tags": [
[ "i", "<data>", "<input-type>", "<relay>", "<marker>" ], [
[ "output", "<mime-type>" ], "i",
[ "relays", "wss://..." ], "<data>",
[ "bid", "<msat-amount>" ], "<input-type>",
[ "t", "bitcoin" ] "<relay>",
"<marker>"
],
[
"output",
"<mime-type>"
],
[
"relays",
"wss://..."
],
[
"bid",
"<msat-amount>"
],
[
"t",
"bitcoin"
]
] ]
} }
``` ```
@ -57,29 +85,64 @@ All tags are optional.
* `<input-type>`: The way this argument should be interpreted. MUST be one of: * `<input-type>`: The way this argument should be interpreted. MUST be one of:
* `url`: A URL to be fetched of the data that should be processed. * `url`: A URL to be fetched of the data that should be processed.
* `event`: A Nostr event ID. * `event`: A Nostr event ID.
* `job`: The output of a previous job with the specified event ID. The dermination of which output to build upon is up to the service provider to decide (e.g. waiting for a signaling from the customer, waiting for a payment, etc.) * `job`: The output of a previous job with the specified event ID. The dermination of which output to build upon
is up to the service provider to decide (e.g. waiting for a signaling from the customer, waiting for a
payment, etc.)
* `text`: `<data>` is the value of the input, no resolution is needed * `text`: `<data>` is the value of the input, no resolution is needed
* `<relay>`: If `event` or `job` input-type, the relay where the event/job was published, otherwise optional or empty string * `<relay>`: If `event` or `job` input-type, the relay where the event/job was published, otherwise optional or
empty string
* `<marker>`: An optional field indicating how this input should be used within the context of the job * `<marker>`: An optional field indicating how this input should be used within the context of the job
* `output`: Expected output format. Different job request `kind` defines this more precisely. * `output`: Expected output format. Different job request `kind` defines this more precisely.
* `param`: Optional parameters for the job as key (first argument)/value (second argument). Different job request `kind` defines this more precisely. (e.g. `[ "param", "lang", "es" ]`) * `param`: Optional parameters for the job as key (first argument)/value (second argument). Different job request `kind`
defines this more precisely. (e.g. `[ "param", "lang", "es" ]`)
* `bid`: Customer MAY specify a maximum amount (in millisats) they are willing to pay * `bid`: Customer MAY specify a maximum amount (in millisats) they are willing to pay
* `relays`: List of relays where Service Providers SHOULD publish responses to * `relays`: List of relays where Service Providers SHOULD publish responses to
* `p`: Service Providers the customer is interested in. Other SPs MIGHT still choose to process the job * `p`: Service Providers the customer is interested in. Other SPs MIGHT still choose to process the job
## Encrypted Params ## Encrypted Params
If the user wants to keep the input parameters a secret, they can encrypt the `i` and `param` tags with the service provider's 'p' tag and add it to the content field. Add a tag `encrypted` as tags. Encryption for private tags will use [NIP-04 - Encrypted Direct Message encryption](https://github.com/nostr-protocol/nips/blob/master/04.md), using the user's private and service provider's public key for the shared secret If the user wants to keep the input parameters a secret, they can encrypt the `i` and `param` tags with the service
provider's 'p' tag and add it to the content field. Add a tag `encrypted` as tags. Encryption for private tags will
use [NIP-04 - Encrypted Direct Message encryption](https://github.com/nostr-protocol/nips/blob/master/04.md), using the
user's private and service provider's public key for the shared secret
```json ```json
[ [
["i", "what is the capital of France? ", "text"], [
["param", "model", "LLaMA-2"], "i",
["param", "max_tokens", "512"], "what is the capital of France? ",
["param", "temperature", "0.5"], "text"
["param", "top-k", "50"], ],
["param", "top-p", "0.7"], [
["param", "frequency_penalty", "1"] "param",
"model",
"LLaMA-2"
],
[
"param",
"max_tokens",
"512"
],
[
"param",
"temperature",
"0.5"
],
[
"param",
"top-k",
"50"
],
[
"param",
"top-p",
"0.7"
],
[
"param",
"frequency_penalty",
"1"
]
] ]
``` ```
@ -90,17 +153,22 @@ This param data will be encrypted and added to the `content` field and `p` tag s
{ {
"content": "BE2Y4xvS6HIY7TozIgbEl3sAHkdZoXyLRRkZv4fLPh3R7LtviLKAJM5qpkC7D6VtMbgIt4iNcMpLtpo...", "content": "BE2Y4xvS6HIY7TozIgbEl3sAHkdZoXyLRRkZv4fLPh3R7LtviLKAJM5qpkC7D6VtMbgIt4iNcMpLtpo...",
"tags": [ "tags": [
["p", "04f74530a6ede6b24731b976b8e78fb449ea61f40ff10e3d869a3030c4edc91f"], [
["encrypted"] "p",
"04f74530a6ede6b24731b976b8e78fb449ea61f40ff10e3d869a3030c4edc91f"
],
[
"encrypted"
]
], ],
... ...
} }
``` ```
## Job result (`kind:6000-6999`) ## Job result (`kind:6000-6999`)
Service providers publish job results, providing the output of the job result. They should tag the original job request event id as well as the customer's pubkey. Service providers publish job results, providing the output of the job result. They should tag the original job request
event id as well as the customer's pubkey.
```json ```json
{ {
@ -108,23 +176,42 @@ Service providers publish job results, providing the output of the job result. T
"content": "<payload>", "content": "<payload>",
"kind": 6xxx, "kind": 6xxx,
"tags": [ "tags": [
["request", "<job-request>"], [
["e", "<job-request-id>", "<relay-hint>"], "request",
["i", "<input-data>"], "<job-request>"
["p", "<customer's-pubkey>"], ],
["amount", "requested-payment-amount", "<optional-bolt11>"] [
"e",
"<job-request-id>",
"<relay-hint>"
],
[
"i",
"<input-data>"
],
[
"p",
"<customer's-pubkey>"
],
[
"amount",
"requested-payment-amount",
"<optional-bolt11>"
]
], ],
... ...
} }
``` ```
* `request`: The job request event stringified-JSON. * `request`: The job request event stringified-JSON.
* `amount`: millisats that the Service Provider is requesting to be paid. An optional third value can be a bolt11 invoice. * `amount`: millisats that the Service Provider is requesting to be paid. An optional third value can be a bolt11
invoice.
* `i`: The original input(s) specified in the request. * `i`: The original input(s) specified in the request.
## Encrypted Output ## Encrypted Output
If the request has encrypted params, then output should be encrypted and placed in `content` field. If the output is encrypted, then avoid including `i` tag with input-data as clear text. If the request has encrypted params, then output should be encrypted and placed in `content` field. If the output is
encrypted, then avoid including `i` tag with input-data as clear text.
Add a tag encrypted to mark the output content as `encrypted` Add a tag encrypted to mark the output content as `encrypted`
```json ```json
@ -133,11 +220,27 @@ Add a tag encrypted to mark the output content as `encrypted`
"content": "<encrypted payload>", "content": "<encrypted payload>",
"kind": 6xxx, "kind": 6xxx,
"tags": [ "tags": [
["request", "<job-request>"], [
["e", "<job-request-id>", "<relay-hint>"], "request",
["p", "<customer's-pubkey>"], "<job-request>"
["amount", "requested-payment-amount", "<optional-bolt11>"], ],
["encrypted"] [
"e",
"<job-request-id>",
"<relay-hint>"
],
[
"p",
"<customer's-pubkey>"
],
[
"amount",
"requested-payment-amount",
"<optional-bolt11>"
],
[
"encrypted"
]
], ],
... ...
} }
@ -152,10 +255,25 @@ Service providers can give feedback about a job back to the customer.
"kind": 7000, "kind": 7000,
"content": "<empty-or-payload>", "content": "<empty-or-payload>",
"tags": [ "tags": [
["status", "<status>", "<extra-info>"], [
["amount", "requested-payment-amount", "<bolt11>"], "status",
["e", "<job-request-id>", "<relay-hint>"], "<status>",
["p", "<customer's-pubkey>"], "<extra-info>"
],
[
"amount",
"requested-payment-amount",
"<bolt11>"
],
[
"e",
"<job-request-id>",
"<relay-hint>"
],
[
"p",
"<customer's-pubkey>"
]
], ],
... ...
} }
@ -163,59 +281,88 @@ Service providers can give feedback about a job back to the customer.
* `content`: Either empty or a job-result (e.g. for partial-result samples) * `content`: Either empty or a job-result (e.g. for partial-result samples)
* `amount` tag: as defined in the [Job Result](#job-result-kind6000-6999) section. * `amount` tag: as defined in the [Job Result](#job-result-kind6000-6999) section.
* `status` tag: Service Providers SHOULD indicate what this feedback status refers to. [Job Feedback Status](#job-feedback-status) defines status. Extra human-readable information can be added as an extra argument. * `status` tag: Service Providers SHOULD indicate what this feedback status refers
to. [Job Feedback Status](#job-feedback-status) defines status. Extra human-readable information can be added as an
extra argument.
* NOTE: If the input params requires input to be encrypted, then `content` field will have encrypted payload with `p` tag as key. * NOTE: If the input params requires input to be encrypted, then `content` field will have encrypted payload with `p`tag
as key.
### Job feedback status ### Job feedback status
| status | description | | status | description |
| -------- | ------------- | |--------------------|-------------------------------------------------------------------------------------------------------------|
| `payment-required` | Service Provider requires payment before continuing. | | `payment-required` | Service Provider requires payment before continuing. |
| `processing` | Service Provider is processing the job. | | `processing` | Service Provider is processing the job. |
| `error` | Service Provider was unable to process the job. | | `error` | Service Provider was unable to process the job. |
| `success` | Service Provider successfully processed the job. | | `success` | Service Provider successfully processed the job. |
| `partial` | Service Provider partially processed the job. The `.content` might include a sample of the partial results. | | `partial` | Service Provider partially processed the job. The `.content` might include a sample of the partial results. |
Any job feedback event MIGHT include results in the `.content` field, as described in the [Job Result](#job-result-kind6000-6999) section. This is useful for service providers to provide a sample of the results that have been processed so far. Any job feedback event MIGHT include results in the `.content` field, as described in
the [Job Result](#job-result-kind6000-6999) section. This is useful for service providers to provide a sample of the
results that have been processed so far.
# Protocol Flow # Protocol Flow
* Customer publishes a job request (e.g. `kind:5000` speech-to-text). * Customer publishes a job request (e.g. `kind:5000` speech-to-text).
* Service Providers MAY submit `kind:7000` job-feedback events (e.g. `payment-required`, `processing`, `error`, etc.). * Service Providers MAY submit `kind:7000` job-feedback events (e.g. `payment-required`, `processing`, `error`, etc.).
* Upon completion, the service provider publishes the result of the job with a `kind:6000` job-result event. * Upon completion, the service provider publishes the result of the job with a `kind:6000` job-result event.
* At any point, if there is an `amount` pending to be paid as instructed by the service provider, the user can pay the included `bolt11` or zap the job result event the service provider has sent to the user * At any point, if there is an `amount` pending to be paid as instructed by the service provider, the user can pay the
included `bolt11` or zap the job result event the service provider has sent to the user
Job feedback (`kind:7000`) and Job Results (`kind:6000-6999`) events MAY include an `amount` tag, this can be interpreted as a suggestion to pay. Service Providers MUST use the `payment-required` feedback event to signal that a payment is required and no further actions will be performed until the payment is sent. Job feedback (`kind:7000`) and Job Results (`kind:6000-6999`) events MAY include an `amount` tag, this can be
interpreted as a suggestion to pay. Service Providers MUST use the `payment-required` feedback event to signal that a
payment is required and no further actions will be performed until the payment is sent.
Customers can always either pay the included `bolt11` invoice or zap the event requesting the payment and service providers should monitor for both if they choose to include a bolt11 invoice. Customers can always either pay the included `bolt11` invoice or zap the event requesting the payment and service
providers should monitor for both if they choose to include a bolt11 invoice.
## Notes about the protocol flow ## Notes about the protocol flow
The flow is deliberately ambiguous, allowing vast flexibility for the interaction between customers and service providers so that service providers can model their behavior based on their own decisions/perceptions of risk.
Some service providers might choose to submit a `payment-required` as the first reaction before sending a `processing` or before delivering results, some might choose to serve partial results for the job (e.g. a sample), send a `payment-required` to deliver the rest of the results, and some service providers might choose to assess likelihood of payment based on an npub's past behavior and thus serve the job results before requesting payment for the best possible UX. The flow is deliberately ambiguous, allowing vast flexibility for the interaction between customers and service
providers so that service providers can model their behavior based on their own decisions/perceptions of risk.
Some service providers might choose to submit a `payment-required` as the first reaction before sending a `processing`or
before delivering results, some might choose to serve partial results for the job (e.g. a sample), send a
`payment-required` to deliver the rest of the results, and some service providers might choose to assess likelihood of
payment based on an npub's past behavior and thus serve the job results before requesting payment for the best possible
UX.
It's not up to this NIP to define how individual vending machines should choose to run their business. It's not up to this NIP to define how individual vending machines should choose to run their business.
# Cancellation # Cancellation
A job request might be canceled by publishing a `kind:5` delete request event tagging the job request event. A job request might be canceled by publishing a `kind:5` delete request event tagging the job request event.
# Appendix 1: Job chaining # Appendix 1: Job chaining
A Customer MAY request multiple jobs to be processed as a chain, where the output of a job is the input of another job. (e.g. podcast transcription -> summarization of the transcription). This is done by specifying as input an event id of a different job with the `job` type.
Service Providers MAY begin processing a subsequent job the moment they see the prior job's result, but they will likely wait for a zap to be published first. This introduces a risk that Service Provider of job #1 might delay publishing the zap event in order to have an advantage. This risk is up to Service Providers to mitigate or to decide whether the service provider of job #1 tends to have good-enough results so as to not wait for an explicit zap to assume the job was accepted. A Customer MAY request multiple jobs to be processed as a chain, where the output of a job is the input of another
job. (e.g. podcast transcription -> summarization of the transcription). This is done by specifying as input an event id
of a different job with the `job` type.
Service Providers MAY begin processing a subsequent job the moment they see the prior job's result, but they will likely
wait for a zap to be published first. This introduces a risk that Service Provider of job #1 might delay publishing the
zap event in order to have an advantage. This risk is up to Service Providers to mitigate or to decide whether the
service provider of job #1 tends to have good-enough results so as to not wait for an explicit zap to assume the job was
accepted.
This gives a higher level of flexibility to service providers (which sophisticated service providers would take anyway). This gives a higher level of flexibility to service providers (which sophisticated service providers would take anyway).
# Appendix 2: Service provider discoverability # Appendix 2: Service provider discoverability
Service Providers MAY use NIP-89 announcements to advertise their support for job kinds: Service Providers MAY use NIP-89 announcements to advertise their support for job kinds:
```js ```js
{ {
"kind": 31990, "kind"
"pubkey": "<pubkey>", :
"content": "{ 31990,
"pubkey"
:
"<pubkey>",
"content"
:
"{
\"name\": \"Translating DVM\", \"name\": \"Translating DVM\",
\"picture\": \"https://domain.com/profile.jpg\", \"picture\": \"https://domain.com/profile.jpg\",
\"lud16\": \"zap@address.com\", \"lud16\": \"zap@address.com\",
@ -224,35 +371,59 @@ Service Providers MAY use NIP-89 announcements to advertise their support for jo
\"acceptsNutZaps\": true, \"acceptsNutZaps\": true,
\"personalized\": true, \"personalized\": true,
\"amount\": \"flexible\", \"amount\": \"flexible\",
\"nip90Params\"": { \"nip90Params\""
:
{
\"mode\": { \"mode\": {
\"required\": False, \"required\": False,
\"values\": ["best", "classic", "fast", "negative"], \"values\": ["
\"description\": "Method to do the translation" best
}, ", "
classic
", "
fast
", "
negative
"],
\"description\": "
Method
to
do the translation
"
} }
}", ,
"tags": [ }
}
",
"tags"
:
[
["k", "5005"], // e.g. translation ["k", "5005"], // e.g. translation
["t", "bitcoin"] // e.g. optionally advertises it specializes in bitcoin audio transcription that won't confuse "Drivechains" with "Ridechains" ["t", "bitcoin"] // e.g. optionally advertises it specializes in bitcoin audio transcription that won't confuse "Drivechains" with "Ridechains"
], ],
... ...
} }
``` ```
Params: ### NIP89 Announcement Params:
name: Name of the DVM
picture: Link to a NIP89 preview picture of the DVM
lud16: The DVM's lud16
about: A description of what the DVM does
supportsEncryption: true or false, depending on whether DVM accepts encrypted requests. default: false
acceptsNutZaps: true or false, depending on whether the DVM accepts Nutzaps. default: false
amount: free, flexible, $amountinsats, signal whether the dvm is free, has a flexible price or name the fix amount of sats it will ask for. default: none/unknown
subscription: true or false, signal whether the DVM requires a subscription. default: false
personalized: true or false, signal whether the result is personalized or not (e.g. for feeds). default: false
action: "follow", "unfollow", "mute" "unmute". Signal to a client that it can perform an action with the results, e.g. for a user list. default: none
nip90Params: a list of parameters that change the processing of the DVM, for example a method, model or other specifig input parameters. default: {}
Everything besides name, picture, about and lud16 is optional and clients should assume default params, if not defined otherwise. | param | description | default |
|----------------------|--------------------------------------------------------------------------------------------------------------|---------|
| `name` | Name of the DVM | - |
| `picture` | Link to a NIP89 preview picture of the DVM | - |
| `lud16` | The DVM's zappable lud16 | - |
| `about` | A description of what the DVM does. | - |
| `supportsEncryption` | true or false, depending on whether DVM accepts encrypted requests | false |
| `acceptsNutZaps` | true or false, depending on whether the DVM accepts NIP61 Nutzaps | false |
| `amount` | free, flexible, str($amountinsats). The asking price of the DVM | none |
| `subscription` | true or false, signal whether the DVM requires a subscription | false |
| `personalized` | true or false, signal whether the result is personalized (e.g. for feeds) | false |
| `action` | "follow", "unfollow", "mute" "unmute". Signal to client it can perform an action with the results | none |
| `nip90Params` | a list of parameters that manipulate the DVM's processing, e.g. a method, model or specific input parameters | {} |
Everything besides name, picture, about and lud16 is optional and clients should assume default params, if not defined
otherwise.
Customers can use NIP-89 to see what service providers their follows use. Customers can use NIP-89 to see what service providers their follows use.