Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ If you are new to Lightning, Go, or protocol work, open an issue or a draft PR a

## Quick links

- Protocol draft (LCP v0.2): `docs/protocol/protocol.md`
- Protocol draft (LCP v0.3): `docs/protocol/protocol.md`
- Reference implementation (daemon): `go-lcpd/`
- go-lcpd developer docs: `docs/go-lcpd/docs/`

Expand Down
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,18 @@
LCP (Lightning Compute Protocol) is an application-layer protocol for paying for small compute jobs over Lightning.
It uses BOLT #1 custom messages on a direct Lightning peer connection.

LCP v0.2 defines a quote → pay → stream flow:
LCP v0.3 defines a manifest → call → quote → pay → stream → complete flow:
- Both sides exchange `lcp_manifest` (mandatory) to advertise limits.
- The Requester sends `lcp_quote_request`, then streams the input (`lcp_stream_begin/chunk/end` with `stream_kind=input`).
- The Provider replies with `lcp_quote_response` containing `price_msat`, `terms_hash`, and a BOLT11 invoice.
- After settlement, the Provider streams the result (`stream_kind=result`) and then sends `lcp_result` (terminal completion + metadata).
- The Requester sends `lcp_call`, then streams the request payload (`lcp_stream_begin/chunk/end` with `stream_kind=request`).
- The Provider replies with `lcp_quote` containing `price_msat`, `terms_hash`, and a BOLT11 invoice.
- After settlement, the Provider streams the response (`stream_kind=response`) and then sends `lcp_complete` (terminal completion + metadata).

LCP binds payment to job terms by setting the invoice `description_hash` to `terms_hash`.

Limitations:
- Payloads are limited by the BOLT #1 custom message size (about 65 KB), but v0.2 supports large inputs/results via chunked streams bounded by peer-declared limits (`max_payload_bytes`, `max_stream_bytes`, `max_job_bytes`).
- Payloads are limited by the BOLT #1 custom message size (about 65 KB), but v0.3 supports large request/response bodies via chunked streams bounded by peer-declared limits (`max_payload_bytes`, `max_stream_bytes`, `max_call_bytes`).
- The Requester and Provider must be directly peered. This leaks metadata compared to onion messages or blinded paths.
- Payment happens before execution. This is not an atomic swap (and v0.2 also requires sending the full input stream before quoting).
- Payment happens before execution. This is not an atomic swap (and v0.3 also requires sending the full request stream before quoting).

Reference: BOLT #1 messaging (`https://github.com/lightning/bolts/blob/master/01-messaging.md`).

Expand Down Expand Up @@ -44,7 +44,7 @@ This project is unaudited. Running it against real funds and real peers can lead
- Configuration: [docs/go-lcpd/docs/configuration.md](docs/go-lcpd/docs/configuration.md)
- Background run + logging: [docs/go-lcpd/docs/background.md](docs/go-lcpd/docs/background.md)
- regtest walkthrough: [docs/go-lcpd/docs/regtest.md](docs/go-lcpd/docs/regtest.md)
- Protocol spec (LCP v0.2): [docs/protocol/protocol.md](docs/protocol/protocol.md)
- Protocol spec (LCP v0.3): [docs/protocol/protocol.md](docs/protocol/protocol.md)
- One-shot client (demo): [go-lcpd/tools/lcpd-oneshot](go-lcpd/tools/lcpd-oneshot)

## Docs site (Mintlify)
Expand Down
15 changes: 7 additions & 8 deletions apps/openai-serve/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,8 @@ High-level data flow:

1. Your client calls the OpenAI-compatible HTTP endpoint (`/v1/chat/completions` or `/v1/responses`).
2. `openai-serve` forwards the raw request body bytes as an LCP `openai.chat_completions.v1` or
`openai.responses.v1` task.
3. `openai-serve` forwards the task to a local `lcpd-grpcd` (Requester) over gRPC.
`openai.responses.v1` method call.
3. `openai-serve` forwards the call to a local `lcpd-grpcd` (Requester) over gRPC.
4. The Requester talks to an LCP Provider over Lightning custom messages, requests a quote, pays, and receives the result.
5. `openai-serve` returns the raw Provider response bytes (no re-encoding) and includes LCP metadata in response headers.

Expand Down Expand Up @@ -125,16 +125,15 @@ For a given `model`, the peer is chosen in this order:

1. `OPENAI_SERVE_MODEL_MAP` (`model=peer_id;...`) if the peer is connected/LCP-ready.
2. `OPENAI_SERVE_DEFAULT_PEER_ID` if set and connected/LCP-ready.
3. A peer that advertises the model in `supported_tasks` (if any).
4. Fallback to the first connected peer.
3. A peer that advertises the required method in `supported_methods` (if any).
4. Fallback to any connected peer.

If there are no connected peers, the request fails.

### Model validation

- If `OPENAI_SERVE_MODEL_ALLOWLIST` is set: `model` must be in the allowlist (unless `OPENAI_SERVE_ALLOW_UNLISTED_MODELS=true`).
- Otherwise: if any connected peers advertise `supported_tasks`, the model must be advertised by at least one peer.
If no peers advertise `supported_tasks`, validation is skipped to keep the gateway usable.
- Otherwise: validation is skipped (LCP v0.3 manifests do not advertise models; Providers enforce their own model policies).

## Safety knobs

Expand All @@ -147,15 +146,15 @@ If there are no connected peers, the request fails.
This service treats logs as sensitive.

- Logs MUST NOT contain raw prompts (`messages[].content`) or raw model outputs.
- Logs include only operational metadata (e.g., peer id, job id, price, durations, and byte/token counts).
- Logs include only operational metadata (e.g., peer id, call id, price, durations, and byte/token counts).
- `OPENAI_SERVE_LOG_LEVEL=debug` enables more verbose request logging; keep `info` (default) for production unless needed.

## Response metadata headers

`POST /v1/chat/completions` and `POST /v1/responses` include LCP metadata headers:

- `X-Lcp-Peer-Id`: the chosen Provider peer id
- `X-Lcp-Job-Id`: the job id (hex)
- `X-Lcp-Call-Id`: the call id (hex)
- `X-Lcp-Price-Msat`: the accepted quote price
- `X-Lcp-Terms-Hash`: the accepted quote terms hash (hex)

Expand Down
9 changes: 8 additions & 1 deletion apps/openai-serve/internal/httpapi/constants.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
package httpapi

const contentEncodingIdentity = "identity"
const (
contentEncodingIdentity = "identity"

requestContentTypeJSONUTF8 = "application/json; charset=utf-8"

lcpMethodOpenAIChatCompletionsV1 = "openai.chat_completions.v1"
lcpMethodOpenAIResponsesV1 = "openai.responses.v1"
)
Loading
Loading