CI / test (push) Failing after 6m12s
/v1/openapi.json is the API clients use — OpenAI's endpoints, Anthropic's, and what llmgw adds — in OpenAPI 3.1, generated from internal/clientapi's route table by the generator the admin API's document comes from, now told each document's title, server, token and error. A test reads the router's mux.HandleFunc calls and refuses a route described and not mounted, or mounted and not described. Asked for before there is a key, so it needs none. /docs/api shows it in Swagger UI 5.33.1 (Apache 2.0, served from the gateway as the page's policy requires): Authorize takes a key, Try it out sends to this gateway. Staff are offered the admin API's document too, from /docs/api/admin.json, which nobody else is given. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
111 lines
6.9 KiB
Go
111 lines
6.9 KiB
Go
package clientapi
|
|
|
|
import (
|
|
"encoding/json"
|
|
|
|
"gitea.mynodes.xyz/ilker/llmgw/internal/control/adminapi"
|
|
"gitea.mynodes.xyz/ilker/llmgw/internal/router"
|
|
)
|
|
|
|
type (
|
|
// Route and Param are the admin API's, which one generator reads.
|
|
Route = adminapi.Route
|
|
Param = adminapi.Param
|
|
)
|
|
|
|
// PathParams describes the parameters in Routes' paths.
|
|
var PathParams = map[string]string{
|
|
"files/{id}": "The file's ID, file-….",
|
|
"batches/{id}": "The batch's ID, batch_….",
|
|
"generations/{id}": "The job's ID, job_….",
|
|
"threads/{id}": "The conversation's ID, as sent in x-llmgw-thread.",
|
|
"memory/{key}": "The note's key, chosen by the caller.",
|
|
"collections/{id}": "The collection's ID, its name when that is unique, or ORG/NAME.",
|
|
}
|
|
|
|
// any is a body whose shape is the engine's or the provider's own.
|
|
var anyJSON = json.RawMessage{}
|
|
|
|
// Routes is every endpoint the client API serves, but /health, /ready and
|
|
// /leader, which are a load balancer's and need no key.
|
|
var Routes = []Route{
|
|
{Method: "POST", Path: "/v1/chat/completions", Summary: "A chat turn",
|
|
Description: "A model's name, an alias, or an adapter's name. Fields not listed go to the engine as sent. " +
|
|
"With a knowledge base, x-llmgw-knowledge names the collections to answer from; x-llmgw-thread continues a stored conversation.",
|
|
Request: ChatCompletionRequest{}, Response: ChatCompletion{}, Stream: true},
|
|
{Method: "POST", Path: "/v1/completions", Summary: "A prompt continued",
|
|
Request: CompletionRequest{}, Response: Completion{}, Stream: true},
|
|
{Method: "POST", Path: "/v1/embeddings", Summary: "Vectors for texts",
|
|
Request: EmbeddingRequest{}, Response: EmbeddingList{}},
|
|
{Method: "POST", Path: "/v1/rerank", Summary: "Documents ordered by a query, for a reranker vLLM serves",
|
|
Request: RerankRequest{}, Response: anyJSON},
|
|
{Method: "POST", Path: "/v1/score", Summary: "Pairs of texts scored, for a scorer vLLM serves",
|
|
Request: ScoreRequest{}, Response: anyJSON},
|
|
{Method: "POST", Path: "/v1/audio/transcriptions", Summary: "Speech to text",
|
|
Request: TranscriptionForm{}, Form: true, Response: Transcription{}},
|
|
{Method: "POST", Path: "/v1/audio/translations", Summary: "Speech to English text",
|
|
Request: TranscriptionForm{}, Form: true, Response: Transcription{}},
|
|
{Method: "POST", Path: "/v1/images/generations", Summary: "Pictures, of a model that makes them",
|
|
Description: "Made by ComfyUI. Pictures come back as b64_json and are kept nowhere; x-llmgw-seed says the seed.",
|
|
Request: ImageRequest{}, Response: ImagesResponse{}},
|
|
{Method: "POST", Path: "/v1/3d/generations", Summary: "A 3D model from a picture, as a job",
|
|
Description: "Answered 202 with the job; ask after it until it is completed, then download output_file_id from /v1/files.",
|
|
Request: MeshRequest{}, Response: Job{}, Status: 202},
|
|
{Method: "GET", Path: "/v1/3d/generations", Summary: "The caller's 3D jobs, newest first",
|
|
Query: []Param{
|
|
{Name: "limit", Type: "integer", Description: "The most jobs to answer with, at most 100; 20 when absent."},
|
|
{Name: "after", Description: "A job's ID: those asked for before it."},
|
|
},
|
|
Response: JobList{}},
|
|
{Method: "GET", Path: "/v1/3d/generations/{id}", Summary: "A 3D job: its status, progress and result", Response: Job{}},
|
|
{Method: "POST", Path: "/v1/3d/generations/{id}/cancel", Summary: "Stop a 3D job, in the engine's queue too", Response: Job{}},
|
|
{Method: "POST", Path: "/v1/moderations", Summary: "Texts judged by the guardrails' judge model",
|
|
Request: ModerationRequest{}, Response: ModerationResponse{}},
|
|
{Method: "POST", Path: "/v1/responses", Summary: "OpenAI's Responses API, for Codex and the like",
|
|
Request: ResponsesRequest{}, Response: anyJSON, Stream: true},
|
|
{Method: "POST", Path: "/v1/messages", Summary: "Anthropic's Messages API, for Claude Code and Anthropic's SDKs",
|
|
Description: "The key is sent as x-api-key or as a bearer token.",
|
|
Request: MessagesRequest{}, Response: anyJSON, Stream: true},
|
|
{Method: "POST", Path: "/v1/messages/count_tokens", Summary: "How many tokens a Messages request would be",
|
|
Request: MessagesRequest{}, Response: TokenCount{}},
|
|
{Method: "GET", Path: "/v1/models", Summary: "The models the key may use", Response: ModelList{}},
|
|
{Method: "POST", Path: "/v1/files", Summary: "Upload a file: a batch's input",
|
|
Request: FileForm{}, Form: true, Response: File{}},
|
|
{Method: "GET", Path: "/v1/files", Summary: "The caller's files",
|
|
Query: []Param{{Name: "purpose", Description: "Only files of this purpose: batch, batch_output, job_output."}},
|
|
Response: FileList{}},
|
|
{Method: "GET", Path: "/v1/files/{id}", Summary: "A file", Response: File{}},
|
|
{Method: "GET", Path: "/v1/files/{id}/content", Summary: "A file's content",
|
|
Binary: "application/octet-stream"},
|
|
{Method: "DELETE", Path: "/v1/files/{id}", Summary: "Delete a file", Response: Deleted{}},
|
|
{Method: "POST", Path: "/v1/batches", Summary: "Run a file of requests at the lowest priority",
|
|
Request: BatchRequest{}, Response: Batch{}},
|
|
{Method: "GET", Path: "/v1/batches", Summary: "The caller's batches",
|
|
Query: []Param{
|
|
{Name: "limit", Type: "integer", Description: "The most batches to answer with; 20 when absent."},
|
|
{Name: "after", Description: "A batch's ID: those made before it."},
|
|
},
|
|
Response: BatchList{}},
|
|
{Method: "GET", Path: "/v1/batches/{id}", Summary: "A batch and how far it is", Response: Batch{}},
|
|
{Method: "POST", Path: "/v1/batches/{id}/cancel", Summary: "Stop a batch", Response: Batch{}},
|
|
{Method: "DELETE", Path: "/v1/threads/{id}", Summary: "Forget a stored conversation"},
|
|
{Method: "PUT", Path: "/v1/memory/{key}", Summary: "Keep a note for the project",
|
|
Request: MemoryWrite{}, Response: MemoryNote{}},
|
|
{Method: "GET", Path: "/v1/memory/{key}", Summary: "A note", Response: MemoryNote{}},
|
|
{Method: "GET", Path: "/v1/memory", Summary: "The project's notes", Response: MemoryList{}},
|
|
{Method: "DELETE", Path: "/v1/memory/{key}", Summary: "Forget a note"},
|
|
{Method: "POST", Path: "/mcp", Summary: "The gateway's MCP server: the memory notes as tools",
|
|
Request: MCPRequest{}, Response: anyJSON},
|
|
{Method: "GET", Path: "/me", Summary: "The caller: its key, its place in the tree, its limits and what it has used",
|
|
Response: Me{}},
|
|
{Method: "GET", Path: "/v1/kb/collections", Summary: "The knowledge-base collections the caller may read",
|
|
Response: []router.KBCollectionView{}},
|
|
{Method: "GET", Path: "/v1/kb/collections/{id}/manifest", Summary: "A collection and its documents",
|
|
Response: router.KBManifest{}},
|
|
{Method: "PUT", Path: "/v1/kb/collections/{id}/documents", Summary: "Add or replace a document, read and embedded by the client",
|
|
Request: router.KBPutDocument{}, Response: router.KBPutResult{}},
|
|
{Method: "DELETE", Path: "/v1/kb/collections/{id}/documents", Summary: "Take a document out of a collection",
|
|
Query: []Param{{Name: "name", Required: true, Description: "The document's name, as the manifest lists it."}},
|
|
Response: KBDeleted{}},
|
|
}
|