From 67e950a2009e81df1b8c91b0a2ade0596e83f168 Mon Sep 17 00:00:00 2001
From: pablof7z
Date: Mon, 3 Jul 2023 14:21:13 +0200
Subject: [PATCH 01/20] wip
---
vending-machine.md | 163 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 163 insertions(+)
create mode 100644 vending-machine.md
diff --git a/vending-machine.md b/vending-machine.md
new file mode 100644
index 00000000..273aa28f
--- /dev/null
+++ b/vending-machine.md
@@ -0,0 +1,163 @@
+# NIP-XX: Data Vending Machine
+Money in, data out.
+
+## 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"), but where they don't necessarily care about "who" processes the data.
+
+This NIP is not to be confused with a 1:1 marketplace; but rather, a flow where user announces a desired output, willigness to pay, and service providers compete to fulfill the job requirement in the best way possible.
+
+### Actors
+There are two actors to the workflow described in this NIP:
+* Customers (npubs who request a job)
+* Service providers (npubs who fulfill jobs)
+
+## User flow
+* User publishes a job request
+`{ "kind": 68001, "tags": [ [ "j", "speech-to-text" ], ... ] }`
+
+* Service providers listen for the type of jobs they can perform
+`{"kinds":[68001], "#j": ["speech-to-text", "image-generation", ... ]}`
+
+* When a job comes in, the service providers who opt to attempt to fulfill the request begin processing it
+* Upon completion, the service provider publishes the result of the job with a `job-result` event.
+* Upon acceptance, the user zaps the service provider, tagging the job request
+
+## Kinds
+
+This NIP introduces two new kinds:
+
+* `kind:68001`: Job request -- a request to have a job be processed
+* `kind:68002`: Job result -- a proposal of the resulting job
+
+### Job request
+A request to have data processed -- published by a user
+
+```json
+{
+ "kind": 68001,
+ "content": "",
+ "tags": [
+ // The type data processing the user wants to be performed
+ // on the
+ [ "j", "", "" ],
+ [ "input", "", "", "" ],
+ [ "relays", "wss://..."],
+
+ // stringified sat amount that the user is offering to pay
+ // for this request
+ // should this include an optional max price or is it too
+ // ambiguous?
+ [ "bid", "", [""] ],
+
+ // max timestamp at which the job is no longer to be processed
+ [ "expiration", "" ]
+
+ // p tags
+ [ "p", "service-provider-1" ],
+ [ "p", "service-provider-2" ],
+
+ // NIP-33 d-tag
+ [ "d", ""]
+ ]
+}
+```
+
+#### `content` field
+An optional, human-readable description of what this job is for.
+
+#### `j` tag
+Specifies the job to be executed. A job request MUST have exactly one `j` tag.
+
+A `j` tag MIGHT name a specific model to be used for the computed with.
+
+#### `input` tag
+Specified the input that the job should be executed with.
+
+* ``: The argument for the input
+* ``: The way this argument should be interpreted
+ * Possible values:
+ * `url`: a URL to be fetched
+ * `event`: a different event ID
+ * `job`: the output of a previous job
+* ``:
+
+#### `relays` tag
+A list of relays the service provider should publish its job result to.
+
+#### `p` tags (optional)
+A user might want to explicitly request this job to be processed by specific service provider(s). Other service providers might still choose to compete for this job.
+
+#### `expiration` (optional)
+A user might specify that they will not be interested in results past a certain time (e.g. a time-sensitive job whos value is no longer relevant after some time, like a live transcription service)
+
+### Job result
+The output of processing the data -- published by the
+```json
+{
+ "pubkey": "service-provider",
+
+ // result
+ "content": "",
+ "tags" [
+ // stringified JSON request event
+ [ "request", "<2xxx1-event>" ],
+ [ "e", ],
+ [ "p", "" ],
+ [ "status", "success", ""],
+ [ "payment", "requested-payment-amount" ]
+ ]
+}
+```
+
+### `status` tag
+The service provider might want to return an error to the user in case the job could not be processed correctly
+
+### `payment`
+
+## Job types
+
+This NIP defines some job types, clients SHOULD specify these types for maximum compatibility with service providers. Other job types might be added to this NIP.
+
+### `speech-to-text`
+#### params
+| param | req? | description
+|--------------------------------|------|--------
+| `range` | opt | timestamp range (in seconds) of desired text to be transcribed
+
+### `summarization`
+| param | req? | description
+|--------------------------------|------|--------
+| `length` | opt | desired length
+
+### `translation` -- Translate text to a specific language
+#### params
+| param | req? | description
+|--------------------------------|------|--------
+| `language` | req | desired language in BCP 47 format.
+
+## Job chaining
+A customer CAN request multiple jobs to be chained, so that the output of a job can be the input of the next job. (e.g. summarization of a podcast's transcription). This is done by specifying as `input` an eventID of a different job with the `job` marker.
+
+Service providers might opt to start processing a subsequent job the moment they see the prior job's result, or they might choose to wait for a zap to have been published. This introduces the 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 a explicit zap to assume the job was accepted.
+
+## Job feedback
+> **Warning**
+> Is this hijacking/modifying the meaning of NIP-25 reactions too much?
+
+A user might choose to not accept a job result for any reason. A user can provide feedback via NIP-25 reactions.
+The `content` of the `kind:7` event SHOULD include a description of how the user reacted to the job result, either
+in the form of
+
+
+## Explicitly not addressed in this NIP
+
+### Reputation system
+Service providers are at obvious risk of having their results not compensated. Mitigation of this risk is up to service providers to figure out (i.e. building reputation systems, requiring npub "balances", etc, etc).
+
+It's out of scope (and undesirable) to have this NIP address this issue; the market should.
+
+## Notes
+
+### Multitple job acceptance
+* Nothing prevents a user from accepting multiple job results.
+
From 71803c21a6bdd2413244a47752c129e3c64eaec6 Mon Sep 17 00:00:00 2001
From: pablof7z
Date: Mon, 3 Jul 2023 14:33:17 +0200
Subject: [PATCH 02/20] Add examples
---
vending-machine.md | 84 ++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 82 insertions(+), 2 deletions(-)
diff --git a/vending-machine.md b/vending-machine.md
index 273aa28f..a94cd332 100644
--- a/vending-machine.md
+++ b/vending-machine.md
@@ -77,8 +77,8 @@ Specified the input that the job should be executed with.
* ``: The way this argument should be interpreted
* Possible values:
* `url`: a URL to be fetched
- * `event`: a different event ID
- * `job`: the output of a previous job
+ * `event`: a nostr event ID
+ * `job`: the output of a previous job with the specified event ID
* ``:
#### `relays` tag
@@ -161,3 +161,83 @@ It's out of scope (and undesirable) to have this NIP address this issue; the mar
### Multitple job acceptance
* Nothing prevents a user from accepting multiple job results.
+# Appendix 1: Examples
+
+## Customer wants to get a transcript of a podcast from second 900 to 930.
+
+### `kind:68001`: Job Request
+```json
+{
+ "id": "12345",
+ "pubkey": "abcdef",
+ "content": "I need a transcript of Bitcoin.review",
+ "tags": [
+ [ "j", "speech-to-text" ],
+ [ "params", "range", "900", "930" ],
+ [ "input", "https://bitcoin.review/episode1.mp3", "url" ],
+ [ "bid", "5000", "9000" ]
+ ]
+}
+```
+
+### `kind:1021`: Job fulfillment
+```json
+{
+ "content": "Person 1: blah blah blah",
+ "tags": [
+ ["e", "12345"],
+ ["p", "abcdef"],
+ ["status", "success"]
+ ]
+}
+```
+
+## Customer wants to get a summarization of a podcast
+
+User publishes two job requests at the same time in the order they should be executed.
+
+### `kind:68001`: Job Request #1
+```json
+{
+ "id": "12345",
+ "pubkey": "abcdef",
+ "content": "I need a transcript of Bitcoin.review from second 900 to 930",
+ "tags": [
+ [ "j", "speech-to-text" ],
+ [ "params", "range", "900", "930" ],
+ [ "input", "https://bitcoin.review/episode1.mp3", "url" ],
+ [ "bid", "5000", "9000" ]
+ ]
+}
+```
+
+### `kind:68001`: Job Request #2
+```json
+{
+ "id": "12346",
+ "pubkey": "abcdef",
+ "content": "I need a summarization",
+ "tags": [
+ [ "j", "summarization" ],
+ [ "params", "length", "3 paragraphs" ],
+ [ "input", "12346", "job" ],
+ [ "bid", "300", "900" ]
+ ]
+}
+```
+
+## Customer wants a translation of a note
+### `kind:68001`: Job Request #1
+```json
+{
+ "id": "12346",
+ "pubkey": "abcdef",
+ "content": "",
+ "tags": [
+ [ "j", "translation" ],
+ [ "input", "", "event" ]
+ [ "params", "language", "es_AR" ],
+ [ "bid", "100", "500" ]
+ ]
+}
+```
\ No newline at end of file
From ce552554a08bb5b9878621abfdde3207d54cae62 Mon Sep 17 00:00:00 2001
From: pablof7z
Date: Wed, 5 Jul 2023 11:14:50 +0200
Subject: [PATCH 03/20] wip, part 2
---
vending-machine.md | 206 ++++++++++++++++++++++++++++++---------------
1 file changed, 138 insertions(+), 68 deletions(-)
diff --git a/vending-machine.md b/vending-machine.md
index a94cd332..eb26688d 100644
--- a/vending-machine.md
+++ b/vending-machine.md
@@ -1,8 +1,15 @@
-# NIP-XX: Data Vending Machine
-Money in, data out.
+NIP-XX
+======
+
+Data Vending Machine
+--------------------
+
+`draft` `optional` `author:pablof7z`
+
+This NIP defines the interaction between customers and Service Providers to perform on-demand computation.
## 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"), but where they don't necessarily care about "who" processes the data.
+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 where they don't necessarily care about "who" processes the data.
This NIP is not to be confused with a 1:1 marketplace; but rather, a flow where user announces a desired output, willigness to pay, and service providers compete to fulfill the job requirement in the best way possible.
@@ -11,26 +18,9 @@ There are two actors to the workflow described in this NIP:
* Customers (npubs who request a job)
* Service providers (npubs who fulfill jobs)
-## User flow
-* User publishes a job request
-`{ "kind": 68001, "tags": [ [ "j", "speech-to-text" ], ... ] }`
-
-* Service providers listen for the type of jobs they can perform
-`{"kinds":[68001], "#j": ["speech-to-text", "image-generation", ... ]}`
-
-* When a job comes in, the service providers who opt to attempt to fulfill the request begin processing it
-* Upon completion, the service provider publishes the result of the job with a `job-result` event.
-* Upon acceptance, the user zaps the service provider, tagging the job request
-
-## Kinds
-
-This NIP introduces two new kinds:
-
-* `kind:68001`: Job request -- a request to have a job be processed
-* `kind:68002`: Job result -- a proposal of the resulting job
-
-### Job request
-A request to have data processed -- published by a user
+# Event Kinds
+## Job request
+A request to have data processed -- published by a customer
```json
{
@@ -38,40 +28,35 @@ A request to have data processed -- published by a user
"content": "",
"tags": [
// The type data processing the user wants to be performed
- // on the
- [ "j", "", "" ],
- [ "input", "", "", "" ],
- [ "relays", "wss://..."],
+ [ "j", "", "" ],
- // stringified sat amount that the user is offering to pay
- // for this request
- // should this include an optional max price or is it too
- // ambiguous?
- [ "bid", "", [""] ],
+ // input(s) for the job request
+ [ "i", "", "", "" ],
- // max timestamp at which the job is no longer to be processed
- [ "expiration", "" ]
+ // relays where the job result should be published
+ [ "relays", "wss://..."],
- // p tags
+ // millisats amount that the user is offering to pay
+ [ "bid", "", "" ],
+ [ "exp", "" ],
[ "p", "service-provider-1" ],
[ "p", "service-provider-2" ],
-
- // NIP-33 d-tag
- [ "d", ""]
]
}
```
-#### `content` field
+### `content` field
An optional, human-readable description of what this job is for.
-#### `j` tag
+### `j` tag
Specifies the job to be executed. A job request MUST have exactly one `j` tag.
-A `j` tag MIGHT name a specific model to be used for the computed with.
+A `j` tag MIGHT name a specific model to be used for the computed with as the second value.
-#### `input` tag
-Specified the input that the job should be executed with.
+### `i` (input) tag
+Specifies the input that the job should be executed with. The input is relay-indexable so that clients interested in the exact same job can find it it's result if it's already fulfilled.
+
+A job request CAN have zero or more inputs.
* ``: The argument for the input
* ``: The way this argument should be interpreted
@@ -81,17 +66,20 @@ Specified the input that the job should be executed with.
* `job`: the output of a previous job with the specified event ID
* ``:
-#### `relays` tag
+### `bid` tag
+The user MIGHT specify an amount of millisats they are willing to pay for the job to be processed. The user MIGHT also specify a maximum amount of millisats they are willing to pay.
+
+### `relays` tag
A list of relays the service provider should publish its job result to.
-#### `p` tags (optional)
-A user might want to explicitly request this job to be processed by specific service provider(s). Other service providers might still choose to compete for this job.
+### `p` tags
+A user MIGHT want to explicitly request this job to be processed by specific service provider(s). Other service providers might still choose to compete for this job.
-#### `expiration` (optional)
+### `exp`
A user might specify that they will not be interested in results past a certain time (e.g. a time-sensitive job whos value is no longer relevant after some time, like a live transcription service)
-### Job result
-The output of processing the data -- published by the
+## Job result
+The output of processing the data -- published by the service provider.
```json
{
"pubkey": "service-provider",
@@ -100,19 +88,22 @@ The output of processing the data -- published by the
"content": "",
"tags" [
// stringified JSON request event
- [ "request", "<2xxx1-event>" ],
- [ "e", ],
+ [ "request", "<68001-event>" ],
+ [ "e", ],
[ "p", "" ],
[ "status", "success", ""],
- [ "payment", "requested-payment-amount" ]
+ [ "amount", "requested-payment-amount" ]
]
}
```
-### `status` tag
+The result of the job should be in the `content`. If the output is not text, the `content` field should be empty and an `output` tag should be used instead as described below.
+
+#### `status` tag
The service provider might want to return an error to the user in case the job could not be processed correctly
-### `payment`
+#### `amount`
+The amount of millisats the service provider is requesting to be paid. This amount MIGHT be different than the amount specified by the user in the `bid` tag. The amount SHOULD be less than the maximum amount specified by the user in the `bid` tag.
## Job types
@@ -133,21 +124,52 @@ This NIP defines some job types, clients SHOULD specify these types for maximum
#### params
| param | req? | description
|--------------------------------|------|--------
-| `language` | req | desired language in BCP 47 format.
+| `language` | req | requested language in BCP 47 format.
+
+# Protocol Flow
+* User publishes a job request
+`{ "kind": 68001, "tags": [ [ "j", "speech-to-text" ], ... ] }`
+
+* Service providers listen for the type of jobs they can perform
+`{"kinds":[68001], "#j": ["speech-to-text", "image-generation", ... ]}`
+
+* When a job comes in, the service providers who opt to attempt to fulfill the request begin processing it, or they can react to it with feedback for the user (e.g. _payment required_, _unprocessable entity_, etc.)
+* Upon completion, the service provider publishes the result of the job with a `job-result` event.
+* Upon acceptance, the user zaps the service provider, tagging the job result event.
-## Job chaining
+# Payment
+Customers SHOULD pay service providers whose job results they accept. Users should zap the service provider, tagging the `kind:68002` job result.
+
+
+# Job chaining
A customer CAN request multiple jobs to be chained, so that the output of a job can be the input of the next job. (e.g. summarization of a podcast's transcription). This is done by specifying as `input` an eventID of a different job with the `job` marker.
Service providers might opt to start processing a subsequent job the moment they see the prior job's result, or they might choose to wait for a zap to have been published. This introduces the 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 a explicit zap to assume the job was accepted.
-## Job feedback
+# Reactions
> **Warning**
> Is this hijacking/modifying the meaning of NIP-25 reactions too much?
-A user might choose to not accept a job result for any reason. A user can provide feedback via NIP-25 reactions.
-The `content` of the `kind:7` event SHOULD include a description of how the user reacted to the job result, either
-in the form of
+## Job request reactions
+Service Providers might opt to give feedback about a job.
+
+### E.g. Payment required
+```json
+{
+ "kind": 7,
+ "content": "Please pay 7 sats for job xxxx",
+ "tags": [
+ [ "e", ],
+ [ "status", "payment-required" ],
+ [ "amount", "7000" ],
+ ]
+}
+```
+## Job feedback
+
+A user might choose to not accept a job result for any reason. A user can provide feedback via NIP-25 reactions.
+The `content` of the `kind:7` event SHOULD include a description of how the user reacted to the job result.
## Explicitly not addressed in this NIP
@@ -163,7 +185,7 @@ It's out of scope (and undesirable) to have this NIP address this issue; the mar
# Appendix 1: Examples
-## Customer wants to get a transcript of a podcast from second 900 to 930.
+## Transcript of a podcast from second `900` to `930`.
### `kind:68001`: Job Request
```json
@@ -174,7 +196,7 @@ It's out of scope (and undesirable) to have this NIP address this issue; the mar
"tags": [
[ "j", "speech-to-text" ],
[ "params", "range", "900", "930" ],
- [ "input", "https://bitcoin.review/episode1.mp3", "url" ],
+ [ "i", "https://bitcoin.review/episode1.mp3", "url" ],
[ "bid", "5000", "9000" ]
]
}
@@ -192,7 +214,7 @@ It's out of scope (and undesirable) to have this NIP address this issue; the mar
}
```
-## Customer wants to get a summarization of a podcast
+## Summarization of a podcast
User publishes two job requests at the same time in the order they should be executed.
@@ -205,7 +227,7 @@ User publishes two job requests at the same time in the order they should be exe
"tags": [
[ "j", "speech-to-text" ],
[ "params", "range", "900", "930" ],
- [ "input", "https://bitcoin.review/episode1.mp3", "url" ],
+ [ "i", "https://bitcoin.review/episode1.mp3", "url" ],
[ "bid", "5000", "9000" ]
]
}
@@ -220,13 +242,13 @@ User publishes two job requests at the same time in the order they should be exe
"tags": [
[ "j", "summarization" ],
[ "params", "length", "3 paragraphs" ],
- [ "input", "12346", "job" ],
+ [ "i", "12346", "job" ],
[ "bid", "300", "900" ]
]
}
```
-## Customer wants a translation of a note
+## Translation of a note
### `kind:68001`: Job Request #1
```json
{
@@ -235,9 +257,57 @@ User publishes two job requests at the same time in the order they should be exe
"content": "",
"tags": [
[ "j", "translation" ],
- [ "input", "", "event" ]
+ [ "i", "", "event" ]
[ "params", "language", "es_AR" ],
[ "bid", "100", "500" ]
]
}
-```
\ No newline at end of file
+```
+
+## AI-image of the summarization of 2 podcasts
+
+### `kind:68001`: Job request #1 (transcribe podcast #1)
+```json
+{
+ "id": "123",
+ "tags": [
+ [ "j", "speech-to-text" ],
+ [ "i", "https://example.com/episode1.mp3", "url" ],
+ [ "bid", "100", "500" ]
+ ]
+}
+```
+
+### `kind:68001`: Job request #2 (transcribe podcast #2)
+```json
+{
+ "id": "124",
+ "tags": [
+ [ "j", "speech-to-text" ],
+ [ "i", "https://example.com/episode2.mp3", "url" ],
+ [ "bid", "100", "500" ]
+ ]
+}
+```
+
+### `kind:68001`: Job request #3 (summarize both podcasts into one podcast)
+```json
+{
+ "id": "125",
+ "tags": [
+ [ "j", "summarize" ],
+ [ "param", "length", "1 paragraph" ],
+ [ "i", "123", "job" ],
+ [ "i", "124", "job" ],
+ [ "bid", "100", "500" ]
+ ]
+}
+```
+
+# Notes
+
+* Should there be a possibility of getting the job result delivered encrypted? I don't like it but maybe it should be supported.
+
+* Ambiguity on job acceptance, particularly for job-chaining circumstances is deliberately ambiguous: service providers could wait until explicit job result acceptance / payment to start working on the next item on the chain, or they could start working as soon as they see a result of the previous job computed.
+
+That's up to each service provider to choose how to behave depending on the circumstances. This gives a higher level of flexibility to service providers (which sophisticated service providers would take anyway).
From 667c700c1cab5106655df2de528e960b4875db0d Mon Sep 17 00:00:00 2001
From: gsovereignty
Date: Sat, 8 Jul 2023 18:51:30 +0800
Subject: [PATCH 04/20] Problem: some of the language is inconsistent
---
vending-machine.md | 53 +++++++++++++++++++++++-----------------------
1 file changed, 27 insertions(+), 26 deletions(-)
diff --git a/vending-machine.md b/vending-machine.md
index eb26688d..2f9c0649 100644
--- a/vending-machine.md
+++ b/vending-machine.md
@@ -27,7 +27,7 @@ A request to have data processed -- published by a customer
"kind": 68001,
"content": "",
"tags": [
- // The type data processing the user wants to be performed
+ // The type of data processing the user wants to be performed
[ "j", "", "" ],
// input(s) for the job request
@@ -49,12 +49,12 @@ A request to have data processed -- published by a customer
An optional, human-readable description of what this job is for.
### `j` tag
-Specifies the job to be executed. A job request MUST have exactly one `j` tag.
+Specifies the job to be executed. A job request MUST have exactly one (1) `j` tag.
-A `j` tag MIGHT name a specific model to be used for the computed with as the second value.
+A `j` tag MAY include a second value specifying the name of a model to be used when computing the result.
### `i` (input) tag
-Specifies the input that the job should be executed with. The input is relay-indexable so that clients interested in the exact same job can find it it's result if it's already fulfilled.
+Specifies the input data that the job is to be executed against. The input is relay-indexable so that clients interested in the exact same job can find the input data and the result result (if it's already fulfilled).
A job request CAN have zero or more inputs.
@@ -64,50 +64,51 @@ A job request CAN have zero or more inputs.
* `url`: a URL to be fetched
* `event`: a nostr event ID
* `job`: the output of a previous job with the specified event ID
-* ``:
+* ``: an optional field indicating where the data can be found if it is a subset of the provided values, for example the name of the key(s) in a key/value set, or the start and end positions of the data if it's a bytestream.
### `bid` tag
-The user MIGHT specify an amount of millisats they are willing to pay for the job to be processed. The user MIGHT also specify a maximum amount of millisats they are willing to pay.
+The Customer MAY specify a maximum amount (in millisats) they are willing to pay for the job to be processed.
### `relays` tag
-A list of relays the service provider should publish its job result to.
+The Service Provider SHOULD publish job results to the relays specified in this this tag.
### `p` tags
-A user MIGHT want to explicitly request this job to be processed by specific service provider(s). Other service providers might still choose to compete for this job.
+If a Customer has a preference for specific Service Provider(s) to process this job, they SHOULD indicate this by including the Service Provider(s) pubkey in a `p` tag. This is NOT intended to exclude other Service Providers and they MAY still choose to compete for jobs that have not tagged them.
### `exp`
-A user might specify that they will not be interested in results past a certain time (e.g. a time-sensitive job whos value is no longer relevant after some time, like a live transcription service)
+A Customer MAY indicate that they will not pay for results produced after a specific Block height or Unix Timestamp. This is intended for time-sensitive jobs where the result is not relevant unless produced within a certain timeframe, e.g. a live transcription service.
## Job result
-The output of processing the data -- published by the service provider.
+The output of processing the data -- published by the Service Provider.
```json
{
- "pubkey": "service-provider",
+ "pubkey": "service-provider pubkey in hex",
// result
- "content": "",
+ "content": "string: ",
+ "kind": 68002,
"tags" [
// stringified JSON request event
- [ "request", "<68001-event>" ],
- [ "e", ],
- [ "p", "" ],
- [ "status", "success", ""],
+ [ "request", "" ],
+ [ "e", "" ],
+ [ "p", "" ],
+ [ "status", "success", "" ],
[ "amount", "requested-payment-amount" ]
]
}
```
-The result of the job should be in the `content`. If the output is not text, the `content` field should be empty and an `output` tag should be used instead as described below.
+The result of the job SHOULD be included in the `content` field. If the output is not text, the `content` field SHOULD be empty and an `output` tag should be used instead as described below.
#### `status` tag
-The service provider might want to return an error to the user in case the job could not be processed correctly
+The Service Provider MAY indicate errors during processing by including them in the `status` tag, these errors are intended to be consumed by the Customer.
#### `amount`
-The amount of millisats the service provider is requesting to be paid. This amount MIGHT be different than the amount specified by the user in the `bid` tag. The amount SHOULD be less than the maximum amount specified by the user in the `bid` tag.
+The amount (in millisats) that the Service Provider is requesting to be paid. This amount MAY differ to the amount specified by the Customer in the `bid` tag. The amount SHOULD be less than the maximum amount specified by the user in the `bid` tag.
## Job types
-This NIP defines some job types, clients SHOULD specify these types for maximum compatibility with service providers. Other job types might be added to this NIP.
+This NIP defines some example job types, Customers SHOULD specify these types for maximum compatibility with Service Providers. Other job types MAY be added to this NIP after being observed in the wild.
### `speech-to-text`
#### params
@@ -127,24 +128,24 @@ This NIP defines some job types, clients SHOULD specify these types for maximum
| `language` | req | requested language in BCP 47 format.
# Protocol Flow
-* User publishes a job request
+* Customer publishes a job request
`{ "kind": 68001, "tags": [ [ "j", "speech-to-text" ], ... ] }`
-* Service providers listen for the type of jobs they can perform
+* Service Providers subsribe to the type of jobs they can perform
`{"kinds":[68001], "#j": ["speech-to-text", "image-generation", ... ]}`
-* When a job comes in, the service providers who opt to attempt to fulfill the request begin processing it, or they can react to it with feedback for the user (e.g. _payment required_, _unprocessable entity_, etc.)
+* When a job comes in, the Service Providers who opt to attempt to fulfill the request begin processing it, or they can react to it with feedback for the user (e.g. _payment required_, _unprocessable entity_, etc.)
* Upon completion, the service provider publishes the result of the job with a `job-result` event.
* Upon acceptance, the user zaps the service provider, tagging the job result event.
# Payment
-Customers SHOULD pay service providers whose job results they accept. Users should zap the service provider, tagging the `kind:68002` job result.
+Customers SHOULD pay service providers whose job results they accept by zapping the Service Provider and tagging the `kind:68002` job result.
# Job chaining
-A customer CAN request multiple jobs to be chained, so that the output of a job can be the input of the next job. (e.g. summarization of a podcast's transcription). This is done by specifying as `input` an eventID of a different job with the `job` marker.
+A Customer MAY request multiple jobs to be processed in a chained form, so that the output of a job can be the input of the next job. (e.g. summarization of a podcast's transcription). This is done by specifying as `input` an eventID of a different job with the `job` marker.
-Service providers might opt to start processing a subsequent job the moment they see the prior job's result, or they might choose to wait for a zap to have been published. This introduces the 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 a explicit zap to assume the job was accepted.
+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 a explicit zap to assume the job was accepted.
# Reactions
> **Warning**
From 5f27121c98efe01f756ee8d316051913277b33c5 Mon Sep 17 00:00:00 2001
From: Believethehype
Date: Sun, 9 Jul 2023 12:08:28 +0200
Subject: [PATCH 05/20] Update vending-machine.md
---
vending-machine.md | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/vending-machine.md b/vending-machine.md
index 2f9c0649..e64a667c 100644
--- a/vending-machine.md
+++ b/vending-machine.md
@@ -89,7 +89,7 @@ The output of processing the data -- published by the Service Provider.
"kind": 68002,
"tags" [
// stringified JSON request event
- [ "request", "" ],
+ [ "request", "<68001-event-as-stringified JSON>" ],
[ "e", "" ],
[ "p", "" ],
[ "status", "success", "" ],
@@ -115,6 +115,7 @@ This NIP defines some example job types, Customers SHOULD specify these types fo
| param | req? | description
|--------------------------------|------|--------
| `range` | opt | timestamp range (in seconds) of desired text to be transcribed
+| `alignment` | opt | word, segment, raw : word-level, segment-level or raw outputs
### `summarization`
| param | req? | description
From a9dd5574531229df065eb9df2212bb7510db1f61 Mon Sep 17 00:00:00 2001
From: pablof7z
Date: Tue, 11 Jul 2023 15:22:30 +0200
Subject: [PATCH 06/20] get rid of the kind:7 stuff
---
vending-machine.md | 131 +++++++++++++++++++++------------------------
1 file changed, 61 insertions(+), 70 deletions(-)
diff --git a/vending-machine.md b/vending-machine.md
index e64a667c..0f0b0031 100644
--- a/vending-machine.md
+++ b/vending-machine.md
@@ -33,6 +33,9 @@ A request to have data processed -- published by a customer
// input(s) for the job request
[ "i", "", "", "" ],
+ // expected output format
+ [ "output", "mimetype" ],
+
// relays where the job result should be published
[ "relays", "wss://..."],
@@ -45,51 +48,36 @@ A request to have data processed -- published by a customer
}
```
-### `content` field
-An optional, human-readable description of what this job is for.
-
-### `j` tag
-Specifies the job to be executed. A job request MUST have exactly one (1) `j` tag.
-
-A `j` tag MAY include a second value specifying the name of a model to be used when computing the result.
-
-### `i` (input) tag
-Specifies the input data that the job is to be executed against. The input is relay-indexable so that clients interested in the exact same job can find the input data and the result result (if it's already fulfilled).
+* `content` field: An optional, human-readable description of what this job is for.
+* `j` tag: Job-type to be executed.
+ * A job request MUST have exactly one `j` tag.
+ * It MAY include a second value specifying the name of a model to be used when computing the result.
-A job request CAN have zero or more inputs.
-
-* ``: The argument for the input
-* ``: The way this argument should be interpreted
- * Possible values:
+* `i` tag: Input data for the job.
+ * A job request CAN have zero or more inputs.
+ * Positional arguments: `["i", "", "", "", ""]`
+ * ``: The argument for the input
+ * ``: The way this argument should be interpreted, one of:
* `url`: a URL to be fetched
- * `event`: a nostr event ID
+ * `event`: a nostr event ID, include an optional relay-url extra param
* `job`: the output of a previous job with the specified event ID
-* ``: an optional field indicating where the data can be found if it is a subset of the provided values, for example the name of the key(s) in a key/value set, or the start and end positions of the data if it's a bytestream.
-
-### `bid` tag
-The Customer MAY specify a maximum amount (in millisats) they are willing to pay for the job to be processed.
-
-### `relays` tag
-The Service Provider SHOULD publish job results to the relays specified in this this tag.
-
-### `p` tags
-If a Customer has a preference for specific Service Provider(s) to process this job, they SHOULD indicate this by including the Service Provider(s) pubkey in a `p` tag. This is NOT intended to exclude other Service Providers and they MAY still choose to compete for jobs that have not tagged them.
-
-### `exp`
-A Customer MAY indicate that they will not pay for results produced after a specific Block height or Unix Timestamp. This is intended for time-sensitive jobs where the result is not relevant unless produced within a certain timeframe, e.g. a live transcription service.
+ * ``: if `event` or `job` input-type, the relay where the event/job was published, otherwise optional or empty string.
+ * ``: an optional field indicating how this input should be used.
+* `output` tag: MIME type. Expected output format. Service Providers SHOULD publish the result of the job in this format.
+* `bid` tag: Customer MAY specify a maximum amount (in millisats) they are willing to pay.
+* `relays` tag: relays where Service Providers SHOULD publish responses to.
+* `p` tags: Service Providers the customer is interested in having process this job. Other SP MIGHT still choose to process the job.
+* `exp`: Optional expiration timestamp. Service Providers SHOULD not send results after this timestamp.
## Job result
The output of processing the data -- published by the Service Provider.
```json
{
"pubkey": "service-provider pubkey in hex",
-
- // result
- "content": "string: ",
+ "content": "",
"kind": 68002,
"tags" [
- // stringified JSON request event
- [ "request", "<68001-event-as-stringified JSON>" ],
+ [ "request", "<68001-event>" ],
[ "e", "" ],
[ "p", "" ],
[ "status", "success", "" ],
@@ -98,36 +86,15 @@ The output of processing the data -- published by the Service Provider.
}
```
-The result of the job SHOULD be included in the `content` field. If the output is not text, the `content` field SHOULD be empty and an `output` tag should be used instead as described below.
-
-#### `status` tag
-The Service Provider MAY indicate errors during processing by including them in the `status` tag, these errors are intended to be consumed by the Customer.
-
-#### `amount`
-The amount (in millisats) that the Service Provider is requesting to be paid. This amount MAY differ to the amount specified by the Customer in the `bid` tag. The amount SHOULD be less than the maximum amount specified by the user in the `bid` tag.
-
-## Job types
-
-This NIP defines some example job types, Customers SHOULD specify these types for maximum compatibility with Service Providers. Other job types MAY be added to this NIP after being observed in the wild.
+## Job feedback
+Both customers and service providers can give feedback about a job.
-### `speech-to-text`
-#### params
-| param | req? | description
-|--------------------------------|------|--------
-| `range` | opt | timestamp range (in seconds) of desired text to be transcribed
-| `alignment` | opt | word, segment, raw : word-level, segment-level or raw outputs
+The result of the job SHOULD be included in the `content` field. If the output is not text, the `content` field SHOULD be empty and an `output` tag should be used instead as described below.
-### `summarization`
-| param | req? | description
-|--------------------------------|------|--------
-| `length` | opt | desired length
-
-### `translation` -- Translate text to a specific language
-#### params
-| param | req? | description
-|--------------------------------|------|--------
-| `language` | req | requested language in BCP 47 format.
+* `status` tag: Service Providers MAY indicate errors or extra info about the results by including them in the `status` tag.
+* `amount`: millisats that the Service Provider is requesting to be paid.
+##
# Protocol Flow
* Customer publishes a job request
`{ "kind": 68001, "tags": [ [ "j", "speech-to-text" ], ... ] }`
@@ -142,15 +109,17 @@ This NIP defines some example job types, Customers SHOULD specify these types fo
# Payment
Customers SHOULD pay service providers whose job results they accept by zapping the Service Provider and tagging the `kind:68002` job result.
+Additionally, if a service provider requests full or partial prepayment via a `kind:68003` job-feedback event, the customer SHOULD zap that event to pay the service provider.
+
+# Cancellation
+A `kind:68001` job request might be cancelled by publishing a `kind:5` delete request event tagging the job request event.
# Job chaining
A Customer MAY request multiple jobs to be processed in a chained form, so that the output of a job can be the input of the next job. (e.g. summarization of a podcast's transcription). This is done by specifying as `input` an eventID of a different job with the `job` marker.
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 a explicit zap to assume the job was accepted.
-# Reactions
-> **Warning**
-> Is this hijacking/modifying the meaning of NIP-25 reactions too much?
+# Job Feedback
## Job request reactions
Service Providers might opt to give feedback about a job.
@@ -169,7 +138,6 @@ Service Providers might opt to give feedback about a job.
```
## Job feedback
-
A user might choose to not accept a job result for any reason. A user can provide feedback via NIP-25 reactions.
The `content` of the `kind:7` event SHOULD include a description of how the user reacted to the job result.
@@ -197,21 +165,21 @@ It's out of scope (and undesirable) to have this NIP address this issue; the mar
"content": "I need a transcript of Bitcoin.review",
"tags": [
[ "j", "speech-to-text" ],
- [ "params", "range", "900", "930" ],
[ "i", "https://bitcoin.review/episode1.mp3", "url" ],
- [ "bid", "5000", "9000" ]
+ [ "params", "range", "900", "930" ],
+ [ "bid", "5000", "9000" ],
+ [ "output", "text/plain" ]
]
}
```
-### `kind:1021`: Job fulfillment
+### `kind:68002`: Job fulfillment
```json
{
- "content": "Person 1: blah blah blah",
+ "content": "blah blah blah",
"tags": [
["e", "12345"],
["p", "abcdef"],
- ["status", "success"]
]
}
```
@@ -306,6 +274,29 @@ User publishes two job requests at the same time in the order they should be exe
}
```
+# Appendix 2: Job types
+
+This NIP defines some example job types, Customers SHOULD specify these types for maximum compatibility with Service Providers. Other job types MAY be added to this NIP after being observed in the wild.
+
+### `speech-to-text`
+#### params
+| param | req? | description
+|--------------------------------|------|--------
+| `range` | opt | timestamp range (in seconds) of desired text to be transcribed
+| `alignment` | opt | word, segment, raw : word-level, segment-level or raw outputs
+
+### `summarization`
+| param | req? | description
+|--------------------------------|------|--------
+| `length` | opt | desired length
+
+### `translation` -- Translate text to a specific language
+#### params
+| param | req? | description
+|--------------------------------|------|--------
+| `language` | req | requested language in BCP 47 format.
+
+
# Notes
* Should there be a possibility of getting the job result delivered encrypted? I don't like it but maybe it should be supported.
From def620e1ce4417a4e78b5012c3a43adbe105f43e Mon Sep 17 00:00:00 2001
From: pablof7z
Date: Tue, 11 Jul 2023 22:25:54 +0200
Subject: [PATCH 07/20] more cleanup
---
vending-machine.md | 57 +++++++++++++++++++++++++++++-----------------
1 file changed, 36 insertions(+), 21 deletions(-)
diff --git a/vending-machine.md b/vending-machine.md
index 0f0b0031..8121ffc0 100644
--- a/vending-machine.md
+++ b/vending-machine.md
@@ -27,19 +27,10 @@ A request to have data processed -- published by a customer
"kind": 68001,
"content": "",
"tags": [
- // The type of data processing the user wants to be performed
[ "j", "", "" ],
-
- // input(s) for the job request
[ "i", "", "", "" ],
-
- // expected output format
- [ "output", "mimetype" ],
-
- // relays where the job result should be published
+ [ "output", "" ],
[ "relays", "wss://..."],
-
- // millisats amount that the user is offering to pay
[ "bid", "", "" ],
[ "exp", "" ],
[ "p", "service-provider-1" ],
@@ -94,7 +85,6 @@ The result of the job SHOULD be included in the `content` field. If the output i
* `status` tag: Service Providers MAY indicate errors or extra info about the results by including them in the `status` tag.
* `amount`: millisats that the Service Provider is requesting to be paid.
-##
# Protocol Flow
* Customer publishes a job request
`{ "kind": 68001, "tags": [ [ "j", "speech-to-text" ], ... ] }`
@@ -127,7 +117,7 @@ Service Providers might opt to give feedback about a job.
### E.g. Payment required
```json
{
- "kind": 7,
+ "kind": 68003,
"content": "Please pay 7 sats for job xxxx",
"tags": [
[ "e", ],
@@ -148,11 +138,6 @@ Service providers are at obvious risk of having their results not compensated. M
It's out of scope (and undesirable) to have this NIP address this issue; the market should.
-## Notes
-
-### Multitple job acceptance
-* Nothing prevents a user from accepting multiple job results.
-
# Appendix 1: Examples
## Transcript of a podcast from second `900` to `930`.
@@ -162,7 +147,7 @@ It's out of scope (and undesirable) to have this NIP address this issue; the mar
{
"id": "12345",
"pubkey": "abcdef",
- "content": "I need a transcript of Bitcoin.review",
+ "content": "",
"tags": [
[ "j", "speech-to-text" ],
[ "i", "https://bitcoin.review/episode1.mp3", "url" ],
@@ -173,13 +158,30 @@ It's out of scope (and undesirable) to have this NIP address this issue; the mar
}
```
-### `kind:68002`: Job fulfillment
+### `kind:68003`: Job Feedback: request for (partial) payment
+```json
+{
+ "kind": 68003,
+ "content": "",
+ "tags": [
+ ["e", "12345"],
+ ["p", "abcdef"],
+ ["status", "payment-required"],
+ ["amount", "1000"]
+ ]
+}
+```
+
+* User zaps 1000 sats to event kind:68003.
+
+### `kind:68002`: Job fulfillment + request for remaining payment
```json
{
"content": "blah blah blah",
"tags": [
["e", "12345"],
["p", "abcdef"],
+ ["amount", "6000"]
]
}
```
@@ -208,7 +210,7 @@ User publishes two job requests at the same time in the order they should be exe
{
"id": "12346",
"pubkey": "abcdef",
- "content": "I need a summarization",
+ "content": "",
"tags": [
[ "j", "summarization" ],
[ "params", "length", "3 paragraphs" ],
@@ -227,13 +229,26 @@ User publishes two job requests at the same time in the order they should be exe
"content": "",
"tags": [
[ "j", "translation" ],
- [ "i", "", "event" ]
+ [ "i", "", "event", "wss://relay.nostr.com" ]
[ "params", "language", "es_AR" ],
[ "bid", "100", "500" ]
]
}
```
+### `kind:68003`: Job respomse
+```json
+{
+ "kind": 68003,
+ "content": "Che, que copado, boludo!",
+ "tags": [
+ ["e", "12346"],
+ ["p", "abcdef"],
+ ["amount", "1000"]
+ ]
+}
+```
+
## AI-image of the summarization of 2 podcasts
### `kind:68001`: Job request #1 (transcribe podcast #1)
From e9924bdcde2dc516a891c027bd023f487b73a674 Mon Sep 17 00:00:00 2001
From: pablof7z
Date: Sat, 15 Jul 2023 12:24:32 +0200
Subject: [PATCH 08/20] add optional bolt11
---
vending-machine.md | 24 +++++++++++++++---------
1 file changed, 15 insertions(+), 9 deletions(-)
diff --git a/vending-machine.md b/vending-machine.md
index 8121ffc0..1d08bd23 100644
--- a/vending-machine.md
+++ b/vending-machine.md
@@ -72,7 +72,7 @@ The output of processing the data -- published by the Service Provider.
[ "e", "" ],
[ "p", "" ],
[ "status", "success", "" ],
- [ "amount", "requested-payment-amount" ]
+ [ "amount", "requested-payment-amount", "" ]
]
}
```
@@ -80,21 +80,27 @@ The output of processing the data -- published by the Service Provider.
## Job feedback
Both customers and service providers can give feedback about a job.
-The result of the job SHOULD be included in the `content` field. If the output is not text, the `content` field SHOULD be empty and an `output` tag should be used instead as described below.
+The result of the job SHOULD be included in the `content` field.
* `status` tag: Service Providers MAY indicate errors or extra info about the results by including them in the `status` tag.
-* `amount`: millisats that the Service Provider is requesting to be paid.
+* `amount`: millisats that the Service Provider is requesting to be paid. An optional third value can be a bolt11 invoice.
# Protocol Flow
* Customer publishes a job request
`{ "kind": 68001, "tags": [ [ "j", "speech-to-text" ], ... ] }`
+* Service Prpvoders can submit `kind:68003` job-feedback events (e.g. `payment-required`, `processing`, `unprocessable-entity`, etc.).
+* Upon completion, the service provider publishes the result of the job with a `kind:68002` job-result event.
+* Upon acceptance, the user zaps the service provider, tagging the job result event with a `kind:7` 👍 reaction.
-* Service Providers subsribe to the type of jobs they can perform
-`{"kinds":[68001], "#j": ["speech-to-text", "image-generation", ... ]}`
+`kind:68002` and `kind:68003` events MAY include an `amount` tag, this can be interpreted as a suggestion to pay. Service Providers
+SHOULD use the `payment-required` feedback event to signal that a payment must be done before moving on to the next step.
-* When a job comes in, the Service Providers who opt to attempt to fulfill the request begin processing it, or they can react to it with feedback for the user (e.g. _payment required_, _unprocessable entity_, etc.)
-* Upon completion, the service provider publishes the result of the job with a `job-result` event.
-* Upon acceptance, the user zaps the service provider, tagging the job result event.
+## Notes about the protocol flow
+The flow is deliverately left ambiguos, allowing vast flexibility for the interaction between customers and service providers so that
+service providers can model their behavior based on their own decisions. Some service providers might choose to submit a `payment-required`
+as the first reaction before sending an `processing` or before delivering `kind:68002` results, some might choose to serve partial results
+for the job (e.g. as a sample), send a `payment-required`to deliver the rest of the results, and some service providers might choose to
+assess likelyhood of payment based on an npub's past behavior and thus serve the job results before requesting payment for the best possible UX.
# Payment
Customers SHOULD pay service providers whose job results they accept by zapping the Service Provider and tagging the `kind:68002` job result.
@@ -131,7 +137,7 @@ Service Providers might opt to give feedback about a job.
A user might choose to not accept a job result for any reason. A user can provide feedback via NIP-25 reactions.
The `content` of the `kind:7` event SHOULD include a description of how the user reacted to the job result.
-## Explicitly not addressed in this NIP
+## Not addressed in this NIP
### Reputation system
Service providers are at obvious risk of having their results not compensated. Mitigation of this risk is up to service providers to figure out (i.e. building reputation systems, requiring npub "balances", etc, etc).
From 53bd97373b5442445f5c387945cf5685ac39ab80 Mon Sep 17 00:00:00 2001
From: pablof7z
Date: Sun, 23 Jul 2023 21:28:59 +0200
Subject: [PATCH 09/20] use different kinds per job request type
---
vending-machine.md | 217 ++++++++++++++++++++++++++-------------------
1 file changed, 127 insertions(+), 90 deletions(-)
diff --git a/vending-machine.md b/vending-machine.md
index 1d08bd23..4dbc5a3a 100644
--- a/vending-machine.md
+++ b/vending-machine.md
@@ -8,10 +8,19 @@ Data Vending Machine
This NIP defines the interaction between customers and Service Providers to perform on-demand computation.
+## Kinds
+This NIP reserves the range `65000-69999` for data vending machine use.
+
+| Kind | Description |
+| ---- | ----------- |
+| 65000 | Job feedback |
+| 65001 | Job result |
+| 65002-69999 | Job request kinds |
+
## 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 where they don't necessarily care about "who" processes the data.
-This NIP is not to be confused with a 1:1 marketplace; but rather, a flow where user announces a desired output, willigness to pay, and service providers compete to fulfill the job requirement in the best way possible.
+This NIP is not to be confused with a 1:1 marketplace; but rather, a flow where user announces a desired output, willingness to pay, and service providers compete to fulfill the job requirement in the best way possible.
### Actors
There are two actors to the workflow described in this NIP:
@@ -24,52 +33,44 @@ A request to have data processed -- published by a customer
```json
{
- "kind": 68001,
+ "kind": 6xxxx,
"content": "",
"tags": [
- [ "j", "", "" ],
- [ "i", "", "", "" ],
+ [ "i", "", "", "", "" ],
[ "output", "" ],
[ "relays", "wss://..."],
- [ "bid", "", "" ],
+ [ "bid", "" ],
[ "exp", "" ],
- [ "p", "service-provider-1" ],
- [ "p", "service-provider-2" ],
+ [ "t", "bitcoin" ]
]
}
```
-* `content` field: An optional, human-readable description of what this job is for.
-* `j` tag: Job-type to be executed.
- * A job request MUST have exactly one `j` tag.
- * It MAY include a second value specifying the name of a model to be used when computing the result.
-
-* `i` tag: Input data for the job.
- * A job request CAN have zero or more inputs.
- * Positional arguments: `["i", "", "", "", ""]`
+* `i` tag: Input data for the job, (zero or more inputs may exist)
* ``: The argument for the input
- * ``: The way this argument should be interpreted, one of:
+ * ``: The way this argument should be interpreted, MUST be one of:
* `url`: a URL to be fetched
* `event`: a nostr event ID, include an optional relay-url extra param
* `job`: the output of a previous job with the specified event ID
- * ``: if `event` or `job` input-type, the relay where the event/job was published, otherwise optional or empty string.
+ * `content`:
* ``: an optional field indicating how this input should be used.
-* `output` tag: MIME type. Expected output format. Service Providers SHOULD publish the result of the job in this format.
-* `bid` tag: Customer MAY specify a maximum amount (in millisats) they are willing to pay.
+ * ``: if `event` or `job` input-type, the relay where the event/job was published, otherwise optional or empty string.
+* `output` tag (opt): MIME type. Expected output format. Service Providers SHOULD publish the result of the job in this format if it has been specified.
+* `bid` tag (opt): Customer MAY specify a maximum amount (in millisats) they are willing to pay.
* `relays` tag: relays where Service Providers SHOULD publish responses to.
-* `p` tags: Service Providers the customer is interested in having process this job. Other SP MIGHT still choose to process the job.
-* `exp`: Optional expiration timestamp. Service Providers SHOULD not send results after this timestamp.
+* `p` tags (opt): Service Providers the customer is interested in having process this job. Other SP MIGHT still choose to process the job.
+* `exp` (opt): expiration timestamp. Service Providers SHOULD not send results after this timestamp.
## Job result
The output of processing the data -- published by the Service Provider.
```json
{
- "pubkey": "service-provider pubkey in hex",
+ "pubkey": "",
"content": "",
- "kind": 68002,
+ "kind": 65001,
"tags" [
- [ "request", "<68001-event>" ],
- [ "e", "" ],
+ [ "request", "" ],
+ [ "e", "", "" ],
[ "p", "" ],
[ "status", "success", "" ],
[ "amount", "requested-payment-amount", "" ]
@@ -77,6 +78,9 @@ The output of processing the data -- published by the Service Provider.
}
```
+* `request` tag: The job request event ID.
+* `amount`: millisats that the Service Provider is requesting to be paid. An optional third value can be a bolt11 invoice.
+
## Job feedback
Both customers and service providers can give feedback about a job.
@@ -86,29 +90,25 @@ The result of the job SHOULD be included in the `content` field.
* `amount`: millisats that the Service Provider is requesting to be paid. An optional third value can be a bolt11 invoice.
# Protocol Flow
-* Customer publishes a job request
-`{ "kind": 68001, "tags": [ [ "j", "speech-to-text" ], ... ] }`
-* Service Prpvoders can submit `kind:68003` job-feedback events (e.g. `payment-required`, `processing`, `unprocessable-entity`, etc.).
-* Upon completion, the service provider publishes the result of the job with a `kind:68002` job-result event.
-* Upon acceptance, the user zaps the service provider, tagging the job result event with a `kind:7` 👍 reaction.
+* Customer publishes a job request (e.g. `kind:65002`).
+* Service Prpvoders can submit `kind:65000` job-feedback events (e.g. `payment-required`, `processing`, `error`, etc.).
+* Upon completion, the service provider publishes the result of the job with a `kind:65001` job-result event.
+* At any point, the user can pay the included `bolt11` or zap any of the events the service provider has sent to the user.
-`kind:68002` and `kind:68003` events MAY include an `amount` tag, this can be interpreted as a suggestion to pay. Service Providers
-SHOULD use the `payment-required` feedback event to signal that a payment must be done before moving on to the next step.
+`kind:65000` and `kind:65001` events MAY include an `amount` tag, this can be interpreted as a suggestion to pay. Service Providers SHOULD 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. Custeroms are 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
-The flow is deliverately left ambiguos, allowing vast flexibility for the interaction between customers and service providers so that
-service providers can model their behavior based on their own decisions. Some service providers might choose to submit a `payment-required`
-as the first reaction before sending an `processing` or before delivering `kind:68002` results, some might choose to serve partial results
-for the job (e.g. as a sample), send a `payment-required`to deliver the rest of the results, and some service providers might choose to
-assess likelyhood 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 deliverately ambiguos, allowing vast flexibility for the interaction between customers and service providers so that service providers can model their behavior based on their own decisions. Some service providers might choose to submit a `payment-required` as the first reaction before sending an `processing` or before delivering `kind:65001` results, some might choose to serve partial results for the job (e.g. as a sample), send a `payment-required`to deliver the rest of the results, and some service providers might choose to assess likelyhood 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.
# Payment
-Customers SHOULD pay service providers whose job results they accept by zapping the Service Provider and tagging the `kind:68002` job result.
+Customers SHOULD pay service providers whose job results they accept by either zapping the Service Provider and tagging the `kind:65001` job result or, if included, paying the bolt11 invoice.
-Additionally, if a service provider requests full or partial prepayment via a `kind:68003` job-feedback event, the customer SHOULD zap that event to pay the service provider.
+Additionally, if a service provider requests full or partial prepayment via a `kind:65000` job-feedback event, the customer SHOULD zap that event to pay the service provider.
# Cancellation
-A `kind:68001` job request might be cancelled by publishing a `kind:5` delete request event tagging the job request event.
+A job request might be cancelled by publishing a `kind:5` delete request event tagging the job request event.
# Job chaining
A Customer MAY request multiple jobs to be processed in a chained form, so that the output of a job can be the input of the next job. (e.g. summarization of a podcast's transcription). This is done by specifying as `input` an eventID of a different job with the `job` marker.
@@ -116,17 +116,31 @@ A Customer MAY request multiple jobs to be processed in a chained form, so that
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 a explicit zap to assume the job was accepted.
# Job Feedback
+The parties to a job request can use `kind:65000` to provide feedback about the job, using a `status` tag to indicate the type of feedback.
-## Job request reactions
-Service Providers might opt to give feedback about a job.
+Any job feedback event MIGHT include an `amount` tag, indicating the amount of millisats the party is requesting to be paid. An optional third value can be a bolt11 invoice.
-### E.g. Payment required
+| status | description |
+|--------|-------------|
+| `payment-required` | Service Provider requires payment before continuing. |
+| `processing` | Service Provider is processing the job. |
+| `error` | Service Provider was unable to process the job. |
+| `success` | Service Provider successfully processed the job. |
+| `failure` | Service Provider failed to process the job. |
+| `partial` | Service Provider partially processed the job. The `.content` might include a sample of the partial results. |
+
+Any job feedback event MIGHT include an `amount` tag, as described in the [Job Result](#job-result) section.
+
+Any job feedback event MIGHT include results in the `.content` field, as described in the [Job Result](#job-result) section.
+
+### E.g. Payment required (with sample content)
```json
{
- "kind": 68003,
- "content": "Please pay 7 sats for job xxxx",
+ "kind": 65000,
+ "content": "This is the transcription service that you",
"tags": [
- [ "e", ],
+ [ "e", , ],
+ [ "p", ],
[ "status", "payment-required" ],
[ "amount", "7000" ],
]
@@ -144,153 +158,160 @@ Service providers are at obvious risk of having their results not compensated. M
It's out of scope (and undesirable) to have this NIP address this issue; the market should.
+### Encrypted job requests
+Not to be included in the first draft of this NIP, but encrypted job requests should be added. A few ways:
+* publish job requests with some useful metadata of the job "e.g. length of audio to be transcribed", service providers offer to do the job, the customer replies with a NIP-04-like encrypted job requested encrypted with the service provider's pubkey.
+
# Appendix 1: Examples
## Transcript of a podcast from second `900` to `930`.
-### `kind:68001`: Job Request
+### `kind:65002`: Speech-to-text job request
```json
{
"id": "12345",
"pubkey": "abcdef",
"content": "",
+ "kind": 65002,
"tags": [
- [ "j", "speech-to-text" ],
[ "i", "https://bitcoin.review/episode1.mp3", "url" ],
[ "params", "range", "900", "930" ],
- [ "bid", "5000", "9000" ],
+ [ "output", "text/vtt" ],
+ [ "bid", "50000" ],
[ "output", "text/plain" ]
]
}
```
-### `kind:68003`: Job Feedback: request for (partial) payment
+### `kind:65001`: Job Feedback: request for (partial) payment
+* The SP is signaling here that it won't start processing until 100 sats are paid
```json
{
- "kind": 68003,
+ "kind": 65000,
"content": "",
"tags": [
["e", "12345"],
["p", "abcdef"],
["status", "payment-required"],
- ["amount", "1000"]
+ ["amount", "100000"]
]
}
```
-* User zaps 1000 sats to event kind:68003.
+* User zaps 100 sats to the `kind:65000` job-feedback
-### `kind:68002`: Job fulfillment + request for remaining payment
+### `kind:65001`: Job result + request for remaining payment
```json
{
"content": "blah blah blah",
"tags": [
["e", "12345"],
["p", "abcdef"],
- ["amount", "6000"]
+ ["amount", "400000"]
]
}
```
## Summarization of a podcast
+User publishes two job requests at the same time.
-User publishes two job requests at the same time in the order they should be executed.
-
-### `kind:68001`: Job Request #1
+### `kind:65002`: Job Request #1: speech-to-text
```json
{
"id": "12345",
"pubkey": "abcdef",
+ "kinds" 65002,
"content": "I need a transcript of Bitcoin.review from second 900 to 930",
"tags": [
- [ "j", "speech-to-text" ],
- [ "params", "range", "900", "930" ],
[ "i", "https://bitcoin.review/episode1.mp3", "url" ],
- [ "bid", "5000", "9000" ]
+ [ "output", "text/plain" ],
+ [ "params", "range", "900", "930" ],
+ [ "bid", "100000" ]
]
}
```
-### `kind:68001`: Job Request #2
+### `kind:65003`: Job Request #2: summarization of job #1's result
```json
{
"id": "12346",
"pubkey": "abcdef",
+ "kinds": 65003,
"content": "",
"tags": [
- [ "j", "summarization" ],
- [ "params", "length", "3 paragraphs" ],
[ "i", "12346", "job" ],
- [ "bid", "300", "900" ]
+ [ "output", "text/plain" ],
+ [ "params", "length", "3 paragraphs" ],
+ [ "bid", "10000" ]
]
}
```
## Translation of a note
-### `kind:68001`: Job Request #1
+### `kind:65004`: Job Request #1: translation of an existing note
```json
{
"id": "12346",
"pubkey": "abcdef",
"content": "",
+ "kinds": 65004,
"tags": [
- [ "j", "translation" ],
[ "i", "", "event", "wss://relay.nostr.com" ]
- [ "params", "language", "es_AR" ],
- [ "bid", "100", "500" ]
+ [ "params", "lang", "es_AR" ],
+ [ "bid", "5000" ]
]
}
```
-### `kind:68003`: Job respomse
+### `kind:65001`: Job respomse
```json
{
- "kind": 68003,
+ "kind": 65001,
"content": "Che, que copado, boludo!",
"tags": [
["e", "12346"],
["p", "abcdef"],
- ["amount", "1000"]
+ ["amount", "4000"]
]
}
```
## AI-image of the summarization of 2 podcasts
-### `kind:68001`: Job request #1 (transcribe podcast #1)
+### `kind:65002`: Job request #1 (transcribe podcast #1)
```json
{
"id": "123",
+ "kind" 65002,
"tags": [
- [ "j", "speech-to-text" ],
[ "i", "https://example.com/episode1.mp3", "url" ],
- [ "bid", "100", "500" ]
+ [ "bid", "100000" ]
]
}
```
-### `kind:68001`: Job request #2 (transcribe podcast #2)
+### `kind:65002`: Job request #2 (transcribe podcast #2)
```json
{
"id": "124",
+ "kind" 65002,
"tags": [
- [ "j", "speech-to-text" ],
[ "i", "https://example.com/episode2.mp3", "url" ],
- [ "bid", "100", "500" ]
+ [ "bid", "100000" ]
]
}
```
-### `kind:68001`: Job request #3 (summarize both podcasts into one podcast)
+### `kind:65003`: Job request #3 (summarize both podcasts into one paragraph)
```json
{
"id": "125",
+ "kind": 65003,
"tags": [
- [ "j", "summarize" ],
[ "param", "length", "1 paragraph" ],
[ "i", "123", "job" ],
[ "i", "124", "job" ],
- [ "bid", "100", "500" ]
+ [ "bid", "100000" ]
]
}
```
@@ -299,29 +320,45 @@ User publishes two job requests at the same time in the order they should be exe
This NIP defines some example job types, Customers SHOULD specify these types for maximum compatibility with Service Providers. Other job types MAY be added to this NIP after being observed in the wild.
-### `speech-to-text`
+### speech-to-text: `kind:65002`
#### params
| param | req? | description
|--------------------------------|------|--------
| `range` | opt | timestamp range (in seconds) of desired text to be transcribed
-| `alignment` | opt | word, segment, raw : word-level, segment-level or raw outputs
+| `alignment` | opt | word, segment, raw: word-level, segment-level or raw outputs
-### `summarization`
+### summarization: `kind:65003`
| param | req? | description
|--------------------------------|------|--------
| `length` | opt | desired length
-### `translation` -- Translate text to a specific language
-#### params
+### translation: `kind:65004`
| param | req? | description
|--------------------------------|------|--------
-| `language` | req | requested language in BCP 47 format.
+| `lang` | req | desired language in BCP 47 format.
+### image generation: `kind:65005`
+* `input`
# Notes
-* Should there be a possibility of getting the job result delivered encrypted? I don't like it but maybe it should be supported.
-
-* Ambiguity on job acceptance, particularly for job-chaining circumstances is deliberately ambiguous: service providers could wait until explicit job result acceptance / payment to start working on the next item on the chain, or they could start working as soon as they see a result of the previous job computed.
+* Job acceptance ambiguity, particularly for job-chaining circumstances is deliberate: service providers could wait until explicit job result acceptance / payment to start working on the next item on the chain, or they could start working as soon as they see a result of the previous job computed.
That's up to each service provider to choose how to behave depending on the circumstances. This gives a higher level of flexibility to service providers (which sophisticated service providers would take anyway).
+
+# Appendix 3: Service provider discoverability
+
+Service Providers can use NIP-89 announcements to advertise their support for job kinds:
+
+```json
+{
+ "kind": 31990,
+ "pubkey": ,
+ "tags": [
+ [ "k", 65002 ], // e.g. speech-to-text
+ [ "t", "bitcoin" ] // e.g. optionally advertises it specializes in bitcoin audio transcription that won't confuse "Drivechains" with "Ridechains"
+ ]
+}
+```
+
+Customers can use NIP-89 to see what service providers their follows use.
\ No newline at end of file
From d8b0e7d757206098f65b8ff868e8c59a9ac92ea6 Mon Sep 17 00:00:00 2001
From: pablof7z
Date: Sun, 23 Jul 2023 23:37:20 +0300
Subject: [PATCH 10/20] wip
---
vending-machine.md | 18 ++++++++++--------
1 file changed, 10 insertions(+), 8 deletions(-)
diff --git a/vending-machine.md b/vending-machine.md
index 4dbc5a3a..4934d4c3 100644
--- a/vending-machine.md
+++ b/vending-machine.md
@@ -9,13 +9,13 @@ Data Vending Machine
This NIP defines the interaction between customers and Service Providers to perform on-demand computation.
## Kinds
-This NIP reserves the range `65000-69999` for data vending machine use.
+This NIP reserves the range `65000-66000` for data vending machine use.
| Kind | Description |
| ---- | ----------- |
| 65000 | Job feedback |
| 65001 | Job result |
-| 65002-69999 | Job request kinds |
+| 65002-66000 | Job request kinds |
## 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 where they don't necessarily care about "who" processes the data.
@@ -33,7 +33,7 @@ A request to have data processed -- published by a customer
```json
{
- "kind": 6xxxx,
+ "kind": <65002-66000>,
"content": "",
"tags": [
[ "i", "", "", "", "" ],
@@ -46,6 +46,8 @@ A request to have data processed -- published by a customer
}
```
+All tags are optional.
+
* `i` tag: Input data for the job, (zero or more inputs may exist)
* ``: The argument for the input
* ``: The way this argument should be interpreted, MUST be one of:
@@ -55,11 +57,11 @@ A request to have data processed -- published by a customer
* `content`:
* ``: an optional field indicating how this input should be used.
* ``: if `event` or `job` input-type, the relay where the event/job was published, otherwise optional or empty string.
-* `output` tag (opt): MIME type. Expected output format. Service Providers SHOULD publish the result of the job in this format if it has been specified.
-* `bid` tag (opt): Customer MAY specify a maximum amount (in millisats) they are willing to pay.
-* `relays` tag: relays where Service Providers SHOULD publish responses to.
-* `p` tags (opt): Service Providers the customer is interested in having process this job. Other SP MIGHT still choose to process the job.
-* `exp` (opt): expiration timestamp. Service Providers SHOULD not send results after this timestamp.
+* `output`: MIME type. Expected output format. Service Providers SHOULD publish the result of the job in this format if it has been specified.
+* `bid`: Customer MAY specify a maximum amount (in millisats) they are willing to pay.
+* `relays`: relays where Service Providers SHOULD publish responses to.
+* `p`: Service Providers the customer is interested in. Other SP MIGHT still choose to process the job.
+* `exp`: expiration timestamp. Service Providers SHOULD not send results after this timestamp.
## Job result
The output of processing the data -- published by the Service Provider.
From 280483adc5b2299886e1e15e369557001e8807af Mon Sep 17 00:00:00 2001
From: pablof7z
Date: Sun, 23 Jul 2023 23:58:12 +0300
Subject: [PATCH 11/20] more clarifications
---
vending-machine.md | 68 +++++++++++++++++++++++++++++++++++-----------
1 file changed, 52 insertions(+), 16 deletions(-)
diff --git a/vending-machine.md b/vending-machine.md
index 4934d4c3..c4fdc18c 100644
--- a/vending-machine.md
+++ b/vending-machine.md
@@ -17,6 +17,8 @@ This NIP reserves the range `65000-66000` for data vending machine use.
| 65001 | Job result |
| 65002-66000 | Job request kinds |
+[Appendix 2](#appendix-2-job-types) defines the job types.
+
## 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 where they don't necessarily care about "who" processes the data.
@@ -33,7 +35,7 @@ A request to have data processed -- published by a customer
```json
{
- "kind": <65002-66000>,
+ "kind": xxx, // kind in 65002-66000 range
"content": "",
"tags": [
[ "i", "", "", "", "" ],
@@ -54,8 +56,8 @@ All tags are optional.
* `url`: a URL to be fetched
* `event`: a nostr event ID, include an optional relay-url extra param
* `job`: the output of a previous job with the specified event ID
- * `content`:
- * ``: an optional field indicating how this input should be used.
+ * `text`: `` is the value of the input, no resolution is needed
+ * ``: an optional field indicating how this input should be used within the context of the job.
* ``: if `event` or `job` input-type, the relay where the event/job was published, otherwise optional or empty string.
* `output`: MIME type. Expected output format. Service Providers SHOULD publish the result of the job in this format if it has been specified.
* `bid`: Customer MAY specify a maximum amount (in millisats) they are willing to pay.
@@ -97,7 +99,7 @@ The result of the job SHOULD be included in the `content` field.
* Upon completion, the service provider publishes the result of the job with a `kind:65001` job-result event.
* At any point, the user can pay the included `bolt11` or zap any of the events the service provider has sent to the user.
-`kind:65000` and `kind:65001` events MAY include an `amount` tag, this can be interpreted as a suggestion to pay. Service Providers SHOULD 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. Custeroms are 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.
+`kind:65000` and `kind:65001` events MAY include an `amount` tag, this can be interpreted as a suggestion to pay. Service Providers SHOULD 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 are 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
The flow is deliverately ambiguos, allowing vast flexibility for the interaction between customers and service providers so that service providers can model their behavior based on their own decisions. Some service providers might choose to submit a `payment-required` as the first reaction before sending an `processing` or before delivering `kind:65001` results, some might choose to serve partial results for the job (e.g. as a sample), send a `payment-required`to deliver the rest of the results, and some service providers might choose to assess likelyhood of payment based on an npub's past behavior and thus serve the job results before requesting payment for the best possible UX.
@@ -117,6 +119,8 @@ A Customer MAY request multiple jobs to be processed in a chained form, so that
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 a explicit zap to assume the job was accepted.
+Consult [Appendix 1: Example](#appendix-1-examples)'s [Summarization of a podcast](#summarization-of-a-podcast)
+
# Job Feedback
The parties to a job request can use `kind:65000` to provide feedback about the job, using a `status` tag to indicate the type of feedback.
@@ -215,7 +219,9 @@ Not to be included in the first draft of this NIP, but encrypted job requests sh
```
## Summarization of a podcast
-User publishes two job requests at the same time.
+User publishes two job requests at the same time. A job that transcribes an audio and a job that summarizes the transcription (output of job #1).
+
+User publishes event #1 and #2 together.
### `kind:65002`: Job Request #1: speech-to-text
```json
@@ -223,7 +229,7 @@ User publishes two job requests at the same time.
"id": "12345",
"pubkey": "abcdef",
"kinds" 65002,
- "content": "I need a transcript of Bitcoin.review from second 900 to 930",
+ "content": "",
"tags": [
[ "i", "https://bitcoin.review/episode1.mp3", "url" ],
[ "output", "text/plain" ],
@@ -233,7 +239,7 @@ User publishes two job requests at the same time.
}
```
-### `kind:65003`: Job Request #2: summarization of job #1's result
+### `kind:65002`: Job Request #2: summarization of job #1's result
```json
{
"id": "12346",
@@ -241,7 +247,7 @@ User publishes two job requests at the same time.
"kinds": 65003,
"content": "",
"tags": [
- [ "i", "12346", "job" ],
+ [ "i", "12345", "job" ], // input is the output of job with id 12345
[ "output", "text/plain" ],
[ "params", "length", "3 paragraphs" ],
[ "bid", "10000" ]
@@ -317,30 +323,60 @@ User publishes two job requests at the same time.
]
}
```
+## AI-image of embedded input
-# Appendix 2: Job types
+### `kind:65005`: Job request
+```json
+{
+ "kind": 65004,
+ "tags": [
+ [ "i", "Millions of vending machines, interconnected with tubes with eah other", "text" ],
+ [ "param", "prompt", "photorealistic" ],
+ [ "bid", "500000" ]
+ ]
+}
+```
-This NIP defines some example job types, Customers SHOULD specify these types for maximum compatibility with Service Providers. Other job types MAY be added to this NIP after being observed in the wild.
+### `kind:65006`: Job request #4 (generate image based on the summary)
+```json
+{
+ "id": "126",
+ "kind": 65004,
+ "tags": [
+ [ "i", "125", "job" ],
+ [ "param", "prompt", "photorealistic" ],
+ [ "param", "size", "4000x4000" ],
+ [ "bid", "500000" ]
+ ]
+}
+```
+
+# Appendix 2: Job types
-### speech-to-text: `kind:65002`
-#### params
+This is a list of all the supported job requests
+.
+## speech-to-text: `kind:65002`
+### params
| param | req? | description
|--------------------------------|------|--------
| `range` | opt | timestamp range (in seconds) of desired text to be transcribed
| `alignment` | opt | word, segment, raw: word-level, segment-level or raw outputs
-### summarization: `kind:65003`
+## summarization: `kind:65003`
| param | req? | description
|--------------------------------|------|--------
| `length` | opt | desired length
-### translation: `kind:65004`
+## translation: `kind:65004`
| param | req? | description
|--------------------------------|------|--------
| `lang` | req | desired language in BCP 47 format.
-### image generation: `kind:65005`
-* `input`
+## image generation: `kind:65005`
+| param | req? | description
+|--------------------------------|------|--------
+| `prompt` | opt | extra prompt to be used for the image generation
+| `size` | opt | desired size of the image
# Notes
From 4cb3ac871f1c54d2e845ec8655bf564072377a46 Mon Sep 17 00:00:00 2001
From: pablof7z
Date: Mon, 24 Jul 2023 00:38:47 +0300
Subject: [PATCH 12/20] clarifications, hopefully
---
vending-machine.md | 180 ++++++++++++++++++++++-----------------------
1 file changed, 87 insertions(+), 93 deletions(-)
diff --git a/vending-machine.md b/vending-machine.md
index c4fdc18c..276132df 100644
--- a/vending-machine.md
+++ b/vending-machine.md
@@ -1,4 +1,4 @@
-NIP-XX
+NIP-90
======
Data Vending Machine
@@ -6,7 +6,9 @@ Data Vending Machine
`draft` `optional` `author:pablof7z`
-This NIP defines the interaction between customers and Service Providers to perform on-demand computation.
+This NIP defines the interaction between customers and Service Providers for performing on-demand computation.
+
+Money in, data out.
## Kinds
This NIP reserves the range `65000-66000` for data vending machine use.
@@ -20,18 +22,18 @@ This NIP reserves the range `65000-66000` for data vending machine use.
[Appendix 2](#appendix-2-job-types) defines the job types.
## 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 where they don't necessarily care about "who" processes the data.
+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; but rather, a flow where user announces a desired output, willingness to pay, and service providers compete to fulfill the job requirement in the best way possible.
+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
-There are two actors to the workflow described in this NIP:
+There are two actors in the workflow described in this NIP:
* Customers (npubs who request a job)
* Service providers (npubs who fulfill jobs)
# Event Kinds
## Job request
-A request to have data processed -- published by a customer
+A request to have data processed, published by a customer
```json
{
@@ -50,33 +52,34 @@ A request to have data processed -- published by a customer
All tags are optional.
-* `i` tag: Input data for the job, (zero or more inputs may exist)
+* `i` tag: Input data for the job (zero or more inputs may exist)
* ``: The argument for the input
* ``: The way this argument should be interpreted, MUST be one of:
- * `url`: a URL to be fetched
- * `event`: a nostr event ID, include an optional relay-url extra param
- * `job`: the output of a previous job with the specified event ID
+ * `url`: A URL to be fetched
+ * `event`: A Nostr event ID, include an optional relay-url extra param
+ * `job`: The output of a previous job with the specified event ID
* `text`: `` is the value of the input, no resolution is needed
- * ``: an optional field indicating how this input should be used within the context of the job.
- * ``: if `event` or `job` input-type, the relay where the event/job was published, otherwise optional or empty string.
-* `output`: MIME type. Expected output format. Service Providers SHOULD publish the result of the job in this format if it has been specified.
-* `bid`: Customer MAY specify a maximum amount (in millisats) they are willing to pay.
-* `relays`: relays where Service Providers SHOULD publish responses to.
-* `p`: Service Providers the customer is interested in. Other SP MIGHT still choose to process the job.
-* `exp`: expiration timestamp. Service Providers SHOULD not send results after this timestamp.
+ * ``: An optional field indicating how this input should be used within the context of the job
+ * ``: If `event` or `job` input-type, the relay where the event/job was published, otherwise optional or empty string
+* `output`: MIME type. Expected output format. Service Providers SHOULD publish the result of the job in this format if it has been specified
+* `bid`: Customer MAY specify a maximum amount (in millisats) they are willing to pay
+* `relays`: 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
+* `exp`: Expiration timestamp. Service Providers SHOULD not send results after this timestamp
## Job result
+
The output of processing the data -- published by the Service Provider.
+
```json
{
"pubkey": "",
"content": "",
"kind": 65001,
- "tags" [
+ "tags": [
[ "request", "" ],
[ "e", "", "" ],
[ "p", "" ],
- [ "status", "success", "" ],
[ "amount", "requested-payment-amount", "" ]
]
}
@@ -91,53 +94,34 @@ Both customers and service providers can give feedback about a job.
The result of the job SHOULD be included in the `content` field.
* `status` tag: Service Providers MAY indicate errors or extra info about the results by including them in the `status` tag.
-* `amount`: millisats that the Service Provider is requesting to be paid. An optional third value can be a bolt11 invoice.
+* `amount`: as defined in the [Job Result](#job-result) section.
# Protocol Flow
* Customer publishes a job request (e.g. `kind:65002`).
-* Service Prpvoders can submit `kind:65000` job-feedback events (e.g. `payment-required`, `processing`, `error`, etc.).
+* Service Providers can submit `kind:65000` job-feedback events (e.g. `payment-required`, `processing`, `error`, etc.).
* Upon completion, the service provider publishes the result of the job with a `kind:65001` job-result event.
* At any point, the user can pay the included `bolt11` or zap any of the events the service provider has sent to the user.
-`kind:65000` and `kind:65001` events MAY include an `amount` tag, this can be interpreted as a suggestion to pay. Service Providers SHOULD 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 are 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.
+`kind:65000` and `kind:65001` events MAY include an `amount` tag, this can be interpreted as a suggestion to pay. Service Providers SHOULD 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.
## Notes about the protocol flow
-The flow is deliverately ambiguos, allowing vast flexibility for the interaction between customers and service providers so that service providers can model their behavior based on their own decisions. Some service providers might choose to submit a `payment-required` as the first reaction before sending an `processing` or before delivering `kind:65001` results, some might choose to serve partial results for the job (e.g. as a sample), send a `payment-required`to deliver the rest of the results, and some service providers might choose to assess likelyhood 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.
+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.
-# Payment
-Customers SHOULD pay service providers whose job results they accept by either zapping the Service Provider and tagging the `kind:65001` job result or, if included, paying the bolt11 invoice.
+Some service providers might choose to submit a `payment-required` as the first reaction before sending a `processing` or before delivering `kind:65001` results, some might choose to serve partial results for the job (e.g. as 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.
-Additionally, if a service provider requests full or partial prepayment via a `kind:65000` job-feedback event, the customer SHOULD zap that event to pay the service provider.
+It's not up to this NIP to define how individual vending machines should choose to run their business.
# Cancellation
A job request might be cancelled by publishing a `kind:5` delete request event tagging the job request event.
# Job chaining
-A Customer MAY request multiple jobs to be processed in a chained form, so that the output of a job can be the input of the next job. (e.g. summarization of a podcast's transcription). This is done by specifying as `input` an eventID of a different job with the `job` marker.
+A Customer MAY request multiple jobs to be processed as a chain, where the output of a job can be 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 a explicit zap to assume the job was accepted.
+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.
-Consult [Appendix 1: Example](#appendix-1-examples)'s [Summarization of a podcast](#summarization-of-a-podcast)
-
-# Job Feedback
-The parties to a job request can use `kind:65000` to provide feedback about the job, using a `status` tag to indicate the type of feedback.
+This gives a higher level of flexibility to service providers (which sophisticated service providers would take anyway).
-Any job feedback event MIGHT include an `amount` tag, indicating the amount of millisats the party is requesting to be paid. An optional third value can be a bolt11 invoice.
-
-| status | description |
-|--------|-------------|
-| `payment-required` | Service Provider requires payment before continuing. |
-| `processing` | Service Provider is processing the job. |
-| `error` | Service Provider was unable to process the job. |
-| `success` | Service Provider successfully processed the job. |
-| `failure` | Service Provider failed to process the job. |
-| `partial` | Service Provider partially processed the job. The `.content` might include a sample of the partial results. |
-
-Any job feedback event MIGHT include an `amount` tag, as described in the [Job Result](#job-result) section.
-
-Any job feedback event MIGHT include results in the `.content` field, as described in the [Job Result](#job-result) section.
+Consult [Appendix 1: Example](#appendix-1-examples)'s [Summarization of a podcast](#summarization-of-a-podcast)
### E.g. Payment required (with sample content)
```json
@@ -153,20 +137,15 @@ Any job feedback event MIGHT include results in the `.content` field, as describ
}
```
-## Job feedback
-A user might choose to not accept a job result for any reason. A user can provide feedback via NIP-25 reactions.
-The `content` of the `kind:7` event SHOULD include a description of how the user reacted to the job result.
-
## Not addressed in this NIP
### Reputation system
-Service providers are at obvious risk of having their results not compensated. Mitigation of this risk is up to service providers to figure out (i.e. building reputation systems, requiring npub "balances", etc, etc).
-
-It's out of scope (and undesirable) to have this NIP address this issue; the market should.
+Service providers are at an obvious risk of having their results not compensated. Mitigation of this risk is up to service providers to figure out (i.e., building reputation systems, requiring npub "balances", etc.). It's out of scope (and undesirable) to have this NIP address this issue; the market should.
### Encrypted job requests
Not to be included in the first draft of this NIP, but encrypted job requests should be added. A few ways:
-* publish job requests with some useful metadata of the job "e.g. length of audio to be transcribed", service providers offer to do the job, the customer replies with a NIP-04-like encrypted job requested encrypted with the service provider's pubkey.
+ * publish job requests with some useful metadata of the job "e.g., length of audio to be transcribed", service providers offer to do the job, the customer replies with a NIP-04-like encrypted job requested encrypted with the service provider's pubkey.
+
# Appendix 1: Examples
@@ -189,7 +168,7 @@ Not to be included in the first draft of this NIP, but encrypted job requests sh
}
```
-### `kind:65001`: Job Feedback: request for (partial) payment
+### `kind:65000`: Job Feedback: request for (partial) payment
* The SP is signaling here that it won't start processing until 100 sats are paid
```json
{
@@ -228,7 +207,7 @@ User publishes event #1 and #2 together.
{
"id": "12345",
"pubkey": "abcdef",
- "kinds" 65002,
+ "kind": 65002,
"content": "",
"tags": [
[ "i", "https://bitcoin.review/episode1.mp3", "url" ],
@@ -244,7 +223,7 @@ User publishes event #1 and #2 together.
{
"id": "12346",
"pubkey": "abcdef",
- "kinds": 65003,
+ "kind": 65003,
"content": "",
"tags": [
[ "i", "12345", "job" ], // input is the output of job with id 12345
@@ -262,16 +241,17 @@ User publishes event #1 and #2 together.
"id": "12346",
"pubkey": "abcdef",
"content": "",
- "kinds": 65004,
+ "kind": 65004,
"tags": [
[ "i", "", "event", "wss://relay.nostr.com" ]
+ [ "output", "text/plain" ],
[ "params", "lang", "es_AR" ],
[ "bid", "5000" ]
]
}
```
-### `kind:65001`: Job respomse
+### `kind:65001`: Job result
```json
{
"kind": 65001,
@@ -290,7 +270,7 @@ User publishes event #1 and #2 together.
```json
{
"id": "123",
- "kind" 65002,
+ "kind": 65002,
"tags": [
[ "i", "https://example.com/episode1.mp3", "url" ],
[ "bid", "100000" ]
@@ -302,7 +282,7 @@ User publishes event #1 and #2 together.
```json
{
"id": "124",
- "kind" 65002,
+ "kind": 65002,
"tags": [
[ "i", "https://example.com/episode2.mp3", "url" ],
[ "bid", "100000" ]
@@ -310,7 +290,7 @@ User publishes event #1 and #2 together.
}
```
-### `kind:65003`: Job request #3 (summarize both podcasts into one paragraph)
+### `kind:65003`: Job request #3 (summarize the two job's outputs into one paragraph)
```json
{
"id": "125",
@@ -323,29 +303,30 @@ User publishes event #1 and #2 together.
]
}
```
-## AI-image of embedded input
-### `kind:65005`: Job request
+### `kind:65005`: Job request #4 (generate image based on the summary)
```json
{
+ "id": "126",
"kind": 65004,
"tags": [
- [ "i", "Millions of vending machines, interconnected with tubes with eah other", "text" ],
+ [ "i", "125", "job" ],
[ "param", "prompt", "photorealistic" ],
+ [ "param", "size", "4000x4000" ],
[ "bid", "500000" ]
]
}
-```
+``
-### `kind:65006`: Job request #4 (generate image based on the summary)
+## AI-image of embedded input
+
+### `kind:65005`: Job request
```json
{
- "id": "126",
"kind": 65004,
"tags": [
- [ "i", "125", "job" ],
+ [ "i", "Millions of vending machines, interconnected with tubes with eah other", "text" ],
[ "param", "prompt", "photorealistic" ],
- [ "param", "size", "4000x4000" ],
[ "bid", "500000" ]
]
}
@@ -353,45 +334,58 @@ User publishes event #1 and #2 together.
# Appendix 2: Job types
-This is a list of all the supported job requests
-.
+This is a list of all the supported job requests.
+
## speech-to-text: `kind:65002`
+
### params
-| param | req? | description
-|--------------------------------|------|--------
-| `range` | opt | timestamp range (in seconds) of desired text to be transcribed
-| `alignment` | opt | word, segment, raw: word-level, segment-level or raw outputs
+
+| param | req? | description |
+|------------|------|-----------------------------------------------------------|
+| `range` | opt | timestamp range (in seconds) of desired text to be transcribed |
+| `alignment`| opt | word, segment, raw: word-level, segment-level, or raw outputs |
## summarization: `kind:65003`
-| param | req? | description
-|--------------------------------|------|--------
-| `length` | opt | desired length
+
+| param | req? | description |
+|-----------|------|---------------|
+| `length` | opt | desired length |
## translation: `kind:65004`
-| param | req? | description
-|--------------------------------|------|--------
-| `lang` | req | desired language in BCP 47 format.
+
+| param | req? | description |
+|-----------|------|--------------------------------------------|
+| `lang` | req | desired language in BCP 47 format. |
## image generation: `kind:65005`
-| param | req? | description
-|--------------------------------|------|--------
-| `prompt` | opt | extra prompt to be used for the image generation
-| `size` | opt | desired size of the image
-# Notes
+| param | req? | description |
+|-----------|------|-------------------------------------------------------|
+| `prompt` | opt | extra prompt to be used for the image generation |
+| `size` | opt | desired size of the image |
+
-* Job acceptance ambiguity, particularly for job-chaining circumstances is deliberate: service providers could wait until explicit job result acceptance / payment to start working on the next item on the chain, or they could start working as soon as they see a result of the previous job computed.
+# Appendix 3: Job feedback status
+
+| status | description |
+|--------|-------------|
+| `payment-required` | Service Provider requires payment before continuing. |
+| `processing` | Service Provider is processing the job. |
+| `error` | Service Provider was unable to process the job. |
+| `success` | Service Provider successfully processed the job. |
+| `failure` | Service Provider failed to process the job. |
+| `partial` | Service Provider partially processed the job. The `.content` might include a sample of the partial results. |
-That's up to each service provider to choose how to behave depending on the circumstances. This gives a higher level of flexibility to service providers (which sophisticated service providers would take anyway).
+Any job feedback event MIGHT include results in the `.content` field, as described in the [Job Result](#job-result) section. This is useful for service providers to provide a sample of the results that have been processed so far.
-# Appendix 3: Service provider discoverability
+# Appendix 4: Service provider discoverability
Service Providers can use NIP-89 announcements to advertise their support for job kinds:
```json
{
"kind": 31990,
- "pubkey": ,
+ "pubkey": "",
"tags": [
[ "k", 65002 ], // e.g. speech-to-text
[ "t", "bitcoin" ] // e.g. optionally advertises it specializes in bitcoin audio transcription that won't confuse "Drivechains" with "Ridechains"
From 723103506030749fc2bba9d5b4ddaf607dd24da3 Mon Sep 17 00:00:00 2001
From: pablof7z
Date: Tue, 25 Jul 2023 01:29:02 +0300
Subject: [PATCH 13/20] feed-generation kind and some more stuff
---
vending-machine.md | 104 ++++++++++++++++++++++++++++++++-------------
1 file changed, 74 insertions(+), 30 deletions(-)
diff --git a/vending-machine.md b/vending-machine.md
index 276132df..c41ccceb 100644
--- a/vending-machine.md
+++ b/vending-machine.md
@@ -19,7 +19,7 @@ This NIP reserves the range `65000-66000` for data vending machine use.
| 65001 | Job result |
| 65002-66000 | Job request kinds |
-[Appendix 2](#appendix-2-job-types) defines the job types.
+[Appendix 2](#appendix-2-job-types) defines the job request types.
## 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.
@@ -32,19 +32,23 @@ There are two actors in the workflow described in this NIP:
* Service providers (npubs who fulfill jobs)
# Event Kinds
+
+* `kind:65000`: job feedback
+* `kind:65001`: job result
+* `kind:65002`-`kind:66000`: job requests
+
## Job request
-A request to have data processed, published by a customer
+A request to have data processed, published by a customer. This event signals that an npub is interested in receiving the result of some kind of compute.
```json
{
- "kind": xxx, // kind in 65002-66000 range
+ "kind": 65xxx, // kind in 65002-66000 range
"content": "",
"tags": [
[ "i", "", "", "", "" ],
[ "output", "" ],
[ "relays", "wss://..."],
[ "bid", "" ],
- [ "exp", "" ],
[ "t", "bitcoin" ]
]
}
@@ -52,24 +56,25 @@ A request to have data processed, published by a customer
All tags are optional.
-* `i` tag: Input data for the job (zero or more inputs may exist)
+* `i` tag: Input data for the job (zero or more inputs)
* ``: The argument for the input
- * ``: The way this argument should be interpreted, MUST be one of:
+ * ``: The way this argument should be interpreted. MUST be one of:
* `url`: A URL to be fetched
- * `event`: A Nostr event ID, include an optional relay-url extra param
+ * `event`: A Nostr event ID.
* `job`: The output of a previous job with the specified event ID
* `text`: `` is the value of the input, no resolution is needed
* ``: An optional field indicating how this input should be used within the context of the job
* ``: If `event` or `job` input-type, the relay where the event/job was published, otherwise optional or empty string
-* `output`: MIME type. Expected output format. Service Providers SHOULD publish the result of the job in this format if it has been specified
+* `output`: Expected output format. (e.g. MIME type)
+ * Service Providers MUST publish the result of the job in this format if it has been specified.
+ * Each job-type ([Appendix 2](#appendix-2-job-types)) might define the output format more narrowly.
* `bid`: Customer MAY specify a maximum amount (in millisats) they are willing to pay
-* `relays`: 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
-* `exp`: Expiration timestamp. Service Providers SHOULD not send results after this timestamp
## Job result
-The output of processing the data -- published by the Service Provider.
+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
{
@@ -79,28 +84,40 @@ The output of processing the data -- published by the Service Provider.
"tags": [
[ "request", "" ],
[ "e", "", "" ],
- [ "p", "" ],
+ [ "p", "" ],
[ "amount", "requested-payment-amount", "" ]
]
}
```
-* `request` tag: The job request event ID.
+* `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.
## Job feedback
-Both customers and service providers can give feedback about a job.
+Service providers can give feedback about a job back to the customer.
-The result of the job SHOULD be included in the `content` field.
+```json
+{
+ "kind": 65000,
+ "content": "",
+ "tags": [
+ [ "status", "", "" ],
+ [ "amount", "requested-payment-amount", "" ],
+ [ "e", "", "" ],
+ [ "p", "" ],
+ ]
+}
+```
-* `status` tag: Service Providers MAY indicate errors or extra info about the results by including them in the `status` tag.
-* `amount`: as defined in the [Job Result](#job-result) section.
+* `content`: Either empty or a job-result (e.g. for partial-result samples)
+* `status` tag: Service Providers SHOULD indicate what this feedback status refers to. [Appendix 3](#appendix-3-job-feedback-status) defines status. Extra human-readable information can be added as an extra argument.
+* `amount` tag: as defined in the [Job Result](#job-result) section.
# Protocol Flow
-* Customer publishes a job request (e.g. `kind:65002`).
+* Customer publishes a job request (e.g. `kind:65002` speech-to-text).
* Service Providers can submit `kind:65000` job-feedback events (e.g. `payment-required`, `processing`, `error`, etc.).
* Upon completion, the service provider publishes the result of the job with a `kind:65001` job-result event.
-* At any point, the user can pay the included `bolt11` or zap any of the events 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
`kind:65000` and `kind:65001` events MAY include an `amount` tag, this can be interpreted as a suggestion to pay. Service Providers SHOULD 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.
@@ -137,16 +154,6 @@ Consult [Appendix 1: Example](#appendix-1-examples)'s [Summarization of a podcas
}
```
-## Not addressed in this NIP
-
-### Reputation system
-Service providers are at an obvious risk of having their results not compensated. Mitigation of this risk is up to service providers to figure out (i.e., building reputation systems, requiring npub "balances", etc.). It's out of scope (and undesirable) to have this NIP address this issue; the market should.
-
-### Encrypted job requests
-Not to be included in the first draft of this NIP, but encrypted job requests should be added. A few ways:
- * publish job requests with some useful metadata of the job "e.g., length of audio to be transcribed", service providers offer to do the job, the customer replies with a NIP-04-like encrypted job requested encrypted with the service provider's pubkey.
-
-
# Appendix 1: Examples
## Transcript of a podcast from second `900` to `930`.
@@ -316,7 +323,7 @@ User publishes event #1 and #2 together.
[ "bid", "500000" ]
]
}
-``
+```
## AI-image of embedded input
@@ -364,6 +371,43 @@ This is a list of all the supported job requests.
| `prompt` | opt | extra prompt to be used for the image generation |
| `size` | opt | desired size of the image |
+## event list generation: `kind:65006`
+
+Generates a list of event ids, (e.g. algorithmic feeds, spam-free notifications, trending topics)
+
+Output should be a stringified array of elements usually find in a nostr event' `tags`, e.g.:
+
+```json
+{ "content": "[
+ [\"e\", \"\"],
+ [\"a\", \"30023:pubkey:id\"],
+ [\"t\", \"tag\"],
+ [\"p\", \"pubkey\"],
+]" }
+```
+
+| param | req? | description |
+|-----------|------|-------------------------------------------------------|
+| `filter` | opt | JSON-stringified `REQ`-like filter
+| `prompt` | opt | A human-readable description of the desired results. Which might be used with e.g. an LLM to tune the results.
+| `p` | opt | Array of pubkeys to generate a feed from someone else's point-of-view. This param allows for a client to choose to generate the feeds and incur the costs of its users.
+
+### example job-request
+
+Generate an algorithmic feed of the most interesting `kind:1`s related to the topic "bitcoin", tagging service providers specializing in safe-for-work content
+that would interest pubkey `pubkey1`.
+
+```json
+{
+ "kind": 65006,
+ "tags": [
+ [ "param", "filter", "{ \"kinds\": [1], \"#t\": [\"bitcoin\"] }" ],
+ [ "param", "p", "[\"pubkey1\"]"]
+ [ "bid", "5000" ],
+ [ "t", "sfw" ]
+ ]
+}
+```
# Appendix 3: Job feedback status
From 948ee24775fe89e779efe7680ca6a27dc5a6207f Mon Sep 17 00:00:00 2001
From: pablof7z
Date: Tue, 25 Jul 2023 17:20:24 +0300
Subject: [PATCH 14/20] rename file
---
vending-machine.md => 90.md | 1 -
README.md | 4 ++++
2 files changed, 4 insertions(+), 1 deletion(-)
rename vending-machine.md => 90.md (99%)
diff --git a/vending-machine.md b/90.md
similarity index 99%
rename from vending-machine.md
rename to 90.md
index c41ccceb..99f313d4 100644
--- a/vending-machine.md
+++ b/90.md
@@ -417,7 +417,6 @@ that would interest pubkey `pubkey1`.
| `processing` | Service Provider is processing the job. |
| `error` | Service Provider was unable to process the job. |
| `success` | Service Provider successfully processed the job. |
-| `failure` | Service Provider failed to process the job. |
| `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) section. This is useful for service providers to provide a sample of the results that have been processed so far.
diff --git a/README.md b/README.md
index 9893ffcf..ebfd3596 100644
--- a/README.md
+++ b/README.md
@@ -64,6 +64,7 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos
- [NIP-65: Relay List Metadata](65.md)
- [NIP-78: Application-specific data](78.md)
- [NIP-89: Recommended Application Handlers](89.md)
+- [NIP-90: Data Vending Machines](90.md)
- [NIP-94: File Metadata](94.md)
- [NIP-98: HTTP Auth](98.md)
@@ -110,6 +111,8 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos
| `30078` | Application-specific Data | [78](78.md) |
| `31989` | Handler recommendation | [89](89.md) |
| `31990` | Handler information | [89](89.md) |
+| `65000` | Job Feedback | [90](90.md) |
+| `65001` | Job Result | [90](90.md) |
### Event Kind Ranges
@@ -119,6 +122,7 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos
| `10000`--`19999` | Replaceable Events | [16](16.md) |
| `20000`--`29999` | Ephemeral Events | [16](16.md) |
| `30000`--`39999` | Parameterized Replaceable Events | [33](33.md) |
+| `65002`--`66000` | Job Requests | [90](90.md) |
## Message types
From 9fa9045d19b93f4cbac231bff39558108a6e82ae Mon Sep 17 00:00:00 2001
From: pablof7z
Date: Tue, 25 Jul 2023 17:31:31 +0300
Subject: [PATCH 15/20] remove duplicated output
---
90.md | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/90.md b/90.md
index 99f313d4..51c49cf2 100644
--- a/90.md
+++ b/90.md
@@ -168,9 +168,8 @@ Consult [Appendix 1: Example](#appendix-1-examples)'s [Summarization of a podcas
"tags": [
[ "i", "https://bitcoin.review/episode1.mp3", "url" ],
[ "params", "range", "900", "930" ],
- [ "output", "text/vtt" ],
+ [ "output", "text/plain" ],
[ "bid", "50000" ],
- [ "output", "text/plain" ]
]
}
```
@@ -388,7 +387,7 @@ Output should be a stringified array of elements usually find in a nostr event'
| param | req? | description |
|-----------|------|-------------------------------------------------------|
-| `filter` | opt | JSON-stringified `REQ`-like filter
+| `filter` | opt | Stringified JSON `REQ` filter. Used to scope the desired results (e.g. specify the desired kinds)
| `prompt` | opt | A human-readable description of the desired results. Which might be used with e.g. an LLM to tune the results.
| `p` | opt | Array of pubkeys to generate a feed from someone else's point-of-view. This param allows for a client to choose to generate the feeds and incur the costs of its users.
From d9400e1e7b08225aedb6c78b522c5ad07b5198b4 Mon Sep 17 00:00:00 2001
From: Pablo Fernandez
Date: Sat, 14 Oct 2023 16:14:24 +0300
Subject: [PATCH 16/20] big refactor
* use different kinds per response type
* remove examples
* remove specific job request definitions, moved to a separate repo for clarity
---
90.md | 371 ++++++++--------------------------------------------------
1 file changed, 52 insertions(+), 319 deletions(-)
diff --git a/90.md b/90.md
index 51c49cf2..4c0eff6a 100644
--- a/90.md
+++ b/90.md
@@ -4,22 +4,24 @@ NIP-90
Data Vending Machine
--------------------
-`draft` `optional` `author:pablof7z`
+`draft` `optional` `author:pablof7z` `author:dontbelievethehype`
This NIP defines the interaction between customers and Service Providers for performing on-demand computation.
Money in, data out.
## Kinds
-This NIP reserves the range `65000-66000` for data vending machine use.
+This NIP reserves the range `5000-7000` for data vending machine use.
| Kind | Description |
| ---- | ----------- |
-| 65000 | Job feedback |
-| 65001 | Job result |
-| 65002-66000 | Job request kinds |
+| 5000-5999 | Job request kinds |
+| 6000-6999 | Job result |
+| 7000 | Job feedback |
-[Appendix 2](#appendix-2-job-types) defines the job request types.
+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).
## 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.
@@ -31,21 +33,15 @@ There are two actors in the workflow described in this NIP:
* Customers (npubs who request a job)
* Service providers (npubs who fulfill jobs)
-# Event Kinds
-
-* `kind:65000`: job feedback
-* `kind:65001`: job result
-* `kind:65002`-`kind:66000`: job requests
-
-## Job request
-A request to have data processed, published by a customer. This event signals that an npub is interested in receiving the result of some kind of compute.
+## Job request (`kind:5000-5999`)
+A request to process data, published by a customer. This event signals that an customer is interested in receiving the result of some kind of compute.
```json
{
- "kind": 65xxx, // kind in 65002-66000 range
+ "kind": 5xxx, // kind in 5000-5999 range
"content": "",
"tags": [
- [ "i", "", "", "", "" ],
+ [ "i", "", "", "", "" ],
[ "output", "" ],
[ "relays", "wss://..."],
[ "bid", "" ],
@@ -59,20 +55,19 @@ All tags are optional.
* `i` tag: Input data for the job (zero or more inputs)
* ``: The argument for the input
* ``: The way this argument should be interpreted. MUST be one of:
- * `url`: A URL to be fetched
+ * `url`: A URL to be fetched of the data that should be processed.
* `event`: A Nostr event ID.
- * `job`: The output of a previous job with the specified 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.)
* `text`: `` is the value of the input, no resolution is needed
- * ``: An optional field indicating how this input should be used within the context of the job
* ``: If `event` or `job` input-type, the relay where the event/job was published, otherwise optional or empty string
-* `output`: Expected output format. (e.g. MIME type)
- * Service Providers MUST publish the result of the job in this format if it has been specified.
- * Each job-type ([Appendix 2](#appendix-2-job-types)) might define the output format more narrowly.
+ * ``: 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.
+* `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
* `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
-## Job result
+## 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.
@@ -80,10 +75,11 @@ Service providers publish job results, providing the output of the job result. T
{
"pubkey": "",
"content": "",
- "kind": 65001,
+ "kind": 6xxx,
"tags": [
[ "request", "" ],
[ "e", "", "" ],
+ [ "i", "" ],
[ "p", "" ],
[ "amount", "requested-payment-amount", "" ]
]
@@ -92,13 +88,14 @@ Service providers publish job results, providing the output of the job result. T
* `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.
+* `i`: The original input(s) specified in the request.
## Job feedback
Service providers can give feedback about a job back to the customer.
```json
{
- "kind": 65000,
+ "kind": 7000,
"content": "",
"tags": [
[ "status", "", "" ],
@@ -110,326 +107,62 @@ 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)
-* `status` tag: Service Providers SHOULD indicate what this feedback status refers to. [Appendix 3](#appendix-3-job-feedback-status) defines status. Extra human-readable information can be added as an extra argument.
* `amount` tag: as defined in the [Job Result](#job-result) section.
+* `status` tag: Service Providers SHOULD indicate what this feedback status refers to. [Appendix 1](#appendix-1-job-feedback-status) defines status. Extra human-readable information can be added as an extra argument.
+
+### Job feedback status
+
+| status | description |
+|--------|-------------|
+| `payment-required` | Service Provider requires payment before continuing. |
+| `processing` | Service Provider is processing the job. |
+| `error` | Service Provider was unable to process 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. |
+
+Any job feedback event MIGHT include results in the `.content` field, as described in the [Job Result](#job-result) section. This is useful for service providers to provide a sample of the results that have been processed so far.
+
# Protocol Flow
-* Customer publishes a job request (e.g. `kind:65002` speech-to-text).
-* Service Providers can submit `kind:65000` job-feedback events (e.g. `payment-required`, `processing`, `error`, etc.).
-* Upon completion, the service provider publishes the result of the job with a `kind:65001` job-result event.
+* 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.).
+* 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
-`kind:65000` and `kind:65001` events MAY include an `amount` tag, this can be interpreted as a suggestion to pay. Service Providers SHOULD 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.
+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.
## 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 `kind:65001` results, some might choose to serve partial results for the job (e.g. as 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.
+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.
# Cancellation
A job request might be cancelled by publishing a `kind:5` delete request event tagging the job request event.
-# Job chaining
-A Customer MAY request multiple jobs to be processed as a chain, where the output of a job can be 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.
+# 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.
This gives a higher level of flexibility to service providers (which sophisticated service providers would take anyway).
-Consult [Appendix 1: Example](#appendix-1-examples)'s [Summarization of a podcast](#summarization-of-a-podcast)
-
-### E.g. Payment required (with sample content)
-```json
-{
- "kind": 65000,
- "content": "This is the transcription service that you",
- "tags": [
- [ "e", , ],
- [ "p", ],
- [ "status", "payment-required" ],
- [ "amount", "7000" ],
- ]
-}
-```
-
-# Appendix 1: Examples
-
-## Transcript of a podcast from second `900` to `930`.
-
-### `kind:65002`: Speech-to-text job request
-```json
-{
- "id": "12345",
- "pubkey": "abcdef",
- "content": "",
- "kind": 65002,
- "tags": [
- [ "i", "https://bitcoin.review/episode1.mp3", "url" ],
- [ "params", "range", "900", "930" ],
- [ "output", "text/plain" ],
- [ "bid", "50000" ],
- ]
-}
-```
-
-### `kind:65000`: Job Feedback: request for (partial) payment
-* The SP is signaling here that it won't start processing until 100 sats are paid
-```json
-{
- "kind": 65000,
- "content": "",
- "tags": [
- ["e", "12345"],
- ["p", "abcdef"],
- ["status", "payment-required"],
- ["amount", "100000"]
- ]
-}
-```
-
-* User zaps 100 sats to the `kind:65000` job-feedback
-
-### `kind:65001`: Job result + request for remaining payment
-```json
-{
- "content": "blah blah blah",
- "tags": [
- ["e", "12345"],
- ["p", "abcdef"],
- ["amount", "400000"]
- ]
-}
-```
-
-## Summarization of a podcast
-User publishes two job requests at the same time. A job that transcribes an audio and a job that summarizes the transcription (output of job #1).
-
-User publishes event #1 and #2 together.
-
-### `kind:65002`: Job Request #1: speech-to-text
-```json
-{
- "id": "12345",
- "pubkey": "abcdef",
- "kind": 65002,
- "content": "",
- "tags": [
- [ "i", "https://bitcoin.review/episode1.mp3", "url" ],
- [ "output", "text/plain" ],
- [ "params", "range", "900", "930" ],
- [ "bid", "100000" ]
- ]
-}
-```
-
-### `kind:65002`: Job Request #2: summarization of job #1's result
-```json
-{
- "id": "12346",
- "pubkey": "abcdef",
- "kind": 65003,
- "content": "",
- "tags": [
- [ "i", "12345", "job" ], // input is the output of job with id 12345
- [ "output", "text/plain" ],
- [ "params", "length", "3 paragraphs" ],
- [ "bid", "10000" ]
- ]
-}
-```
-
-## Translation of a note
-### `kind:65004`: Job Request #1: translation of an existing note
-```json
-{
- "id": "12346",
- "pubkey": "abcdef",
- "content": "",
- "kind": 65004,
- "tags": [
- [ "i", "", "event", "wss://relay.nostr.com" ]
- [ "output", "text/plain" ],
- [ "params", "lang", "es_AR" ],
- [ "bid", "5000" ]
- ]
-}
-```
-
-### `kind:65001`: Job result
-```json
-{
- "kind": 65001,
- "content": "Che, que copado, boludo!",
- "tags": [
- ["e", "12346"],
- ["p", "abcdef"],
- ["amount", "4000"]
- ]
-}
-```
-
-## AI-image of the summarization of 2 podcasts
-
-### `kind:65002`: Job request #1 (transcribe podcast #1)
-```json
-{
- "id": "123",
- "kind": 65002,
- "tags": [
- [ "i", "https://example.com/episode1.mp3", "url" ],
- [ "bid", "100000" ]
- ]
-}
-```
-
-### `kind:65002`: Job request #2 (transcribe podcast #2)
-```json
-{
- "id": "124",
- "kind": 65002,
- "tags": [
- [ "i", "https://example.com/episode2.mp3", "url" ],
- [ "bid", "100000" ]
- ]
-}
-```
-
-### `kind:65003`: Job request #3 (summarize the two job's outputs into one paragraph)
-```json
-{
- "id": "125",
- "kind": 65003,
- "tags": [
- [ "param", "length", "1 paragraph" ],
- [ "i", "123", "job" ],
- [ "i", "124", "job" ],
- [ "bid", "100000" ]
- ]
-}
-```
-
-### `kind:65005`: Job request #4 (generate image based on the summary)
-```json
-{
- "id": "126",
- "kind": 65004,
- "tags": [
- [ "i", "125", "job" ],
- [ "param", "prompt", "photorealistic" ],
- [ "param", "size", "4000x4000" ],
- [ "bid", "500000" ]
- ]
-}
-```
-
-## AI-image of embedded input
-
-### `kind:65005`: Job request
-```json
-{
- "kind": 65004,
- "tags": [
- [ "i", "Millions of vending machines, interconnected with tubes with eah other", "text" ],
- [ "param", "prompt", "photorealistic" ],
- [ "bid", "500000" ]
- ]
-}
-```
-
-# Appendix 2: Job types
-
-This is a list of all the supported job requests.
-
-## speech-to-text: `kind:65002`
-
-### params
-
-| param | req? | description |
-|------------|------|-----------------------------------------------------------|
-| `range` | opt | timestamp range (in seconds) of desired text to be transcribed |
-| `alignment`| opt | word, segment, raw: word-level, segment-level, or raw outputs |
-
-## summarization: `kind:65003`
-
-| param | req? | description |
-|-----------|------|---------------|
-| `length` | opt | desired length |
-
-## translation: `kind:65004`
-
-| param | req? | description |
-|-----------|------|--------------------------------------------|
-| `lang` | req | desired language in BCP 47 format. |
-
-## image generation: `kind:65005`
-
-| param | req? | description |
-|-----------|------|-------------------------------------------------------|
-| `prompt` | opt | extra prompt to be used for the image generation |
-| `size` | opt | desired size of the image |
-
-## event list generation: `kind:65006`
-
-Generates a list of event ids, (e.g. algorithmic feeds, spam-free notifications, trending topics)
-
-Output should be a stringified array of elements usually find in a nostr event' `tags`, e.g.:
-
-```json
-{ "content": "[
- [\"e\", \"\"],
- [\"a\", \"30023:pubkey:id\"],
- [\"t\", \"tag\"],
- [\"p\", \"pubkey\"],
-]" }
-```
-
-| param | req? | description |
-|-----------|------|-------------------------------------------------------|
-| `filter` | opt | Stringified JSON `REQ` filter. Used to scope the desired results (e.g. specify the desired kinds)
-| `prompt` | opt | A human-readable description of the desired results. Which might be used with e.g. an LLM to tune the results.
-| `p` | opt | Array of pubkeys to generate a feed from someone else's point-of-view. This param allows for a client to choose to generate the feeds and incur the costs of its users.
-
-### example job-request
-
-Generate an algorithmic feed of the most interesting `kind:1`s related to the topic "bitcoin", tagging service providers specializing in safe-for-work content
-that would interest pubkey `pubkey1`.
-
-```json
-{
- "kind": 65006,
- "tags": [
- [ "param", "filter", "{ \"kinds\": [1], \"#t\": [\"bitcoin\"] }" ],
- [ "param", "p", "[\"pubkey1\"]"]
- [ "bid", "5000" ],
- [ "t", "sfw" ]
- ]
-}
-```
-
-# Appendix 3: Job feedback status
-
-| status | description |
-|--------|-------------|
-| `payment-required` | Service Provider requires payment before continuing. |
-| `processing` | Service Provider is processing the job. |
-| `error` | Service Provider was unable to process 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. |
-
-Any job feedback event MIGHT include results in the `.content` field, as described in the [Job Result](#job-result) section. This is useful for service providers to provide a sample of the results that have been processed so far.
-
-# Appendix 4: Service provider discoverability
-
-Service Providers can use NIP-89 announcements to advertise their support for job kinds:
+# Appendix 2: Service provider discoverability
+Service Providers MAY use NIP-89 announcements to advertise their support for job kinds:
```json
{
"kind": 31990,
"pubkey": "",
+ "content": "{
+ \"name\": \"Translating DVM\",
+ \"about\": \"I'm a DVM specialized in translating Bitcoin content.\"
+ }",
"tags": [
- [ "k", 65002 ], // e.g. speech-to-text
+ [ "k", 5005 ], // e.g. translation
[ "t", "bitcoin" ] // e.g. optionally advertises it specializes in bitcoin audio transcription that won't confuse "Drivechains" with "Ridechains"
]
}
From 435147149af83cbdbb7a183b9d8769ed1dbb717d Mon Sep 17 00:00:00 2001
From: Pablo Fernandez
Date: Sun, 29 Oct 2023 11:45:49 +0100
Subject: [PATCH 17/20] update readme
---
README.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/README.md b/README.md
index 6f9cb03c..8044b243 100644
--- a/README.md
+++ b/README.md
@@ -97,6 +97,7 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos
| `1984` | Reporting | [56](56.md) |
| `1985` | Label | [32](32.md) |
| `4550` | Community Post Approval | [72](72.md) |
+| `7000` | Job Feedback | [90](90.md) |
| `9041` | Zap Goal | [75](75.md) |
| `9734` | Zap Request | [57](57.md) |
| `9735` | Zap | [57](57.md) |
From ad019ee0670c766b467028e7a55994cea4093a4a Mon Sep 17 00:00:00 2001
From: Akiomi Kamakura
Date: Mon, 30 Oct 2023 11:00:57 +0900
Subject: [PATCH 18/20] DVM kinds change on README (#850)
---
README.md | 2 --
1 file changed, 2 deletions(-)
diff --git a/README.md b/README.md
index 8044b243..8be05951 100644
--- a/README.md
+++ b/README.md
@@ -130,8 +130,6 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos
| `31989` | Handler recommendation | [89](89.md) |
| `31990` | Handler information | [89](89.md) |
| `34550` | Community Definition | [72](72.md) |
-| `65000` | Job Feedback | [90](90.md) |
-| `65001` | Job Result | [90](90.md) |
## Message types
From 4b9f13d983245e4dd166f102308afc28b8bb1603 Mon Sep 17 00:00:00 2001
From: Semisol <45574030+Semisol@users.noreply.github.com>
Date: Tue, 31 Oct 2023 00:21:53 +0300
Subject: [PATCH 19/20] NIP-90: consistency changes
---
90.md | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/90.md b/90.md
index 4c0eff6a..163dbd06 100644
--- a/90.md
+++ b/90.md
@@ -43,7 +43,7 @@ A request to process data, published by a customer. This event signals that an c
"tags": [
[ "i", "", "", "", "" ],
[ "output", "" ],
- [ "relays", "wss://..."],
+ [ "relays", "wss://..." ],
[ "bid", "