api/ai_gateway.proto
Rama main · réplica de lectura del repositorio original.
syntax = "proto3";
package liaison.ai.v1;
option go_package = "github.com/liaisonio/liaison/api/ai/v1";
// HTTP-only supplementary contract, matching agent_settings.proto conventions.
// Management endpoints require current IAM permissions and resource visibility.
// Configuration reads require update permission; workspace requires access use.
// Errors expose error.code and error.request_id, never upstream response bodies.
// Inference errors distinguish UPSTREAM_AUTHENTICATION_FAILED,
// UPSTREAM_MODEL_OR_ENDPOINT_NOT_FOUND, UPSTREAM_RATE_LIMITED and UPSTREAM_TIMEOUT.
// POST /api/v1/ai/accesses/{id}/v1/messages accepts native Anthropic Messages
// only for Anthropic upstreams. Authenticate with a Liaison x-api-key or Bearer
// key (never both). No client beta headers or upstream credentials are forwarded.
// Uses the same key ownership, model allowlist, quota and revocation checks.
// GET/PUT /api/v1/ai/applications/{id}; POST .../{id}/probe
message ApplicationConfig {
string protocol = 1; // API profile: openai includes Responses; openai-compatible is Chat Completions only (default for new OpenAI apps). Other profiles: anthropic, ark, qwen, gemini, ollama.
string base_path = 2;
bool tls = 3;
string api_key = 4; // Write-only; empty preserves. Bound to target fingerprint.
bool clear_key = 5;
bool has_api_key = 6; // Read-only.
string application_type = 7; // Read-only protocol family. OpenAI permits both API profiles; legacy llm remains configurable.
}
// POST /api/v1/ai/setup/probe: connector-only discovery, never persists data.
// POST /api/v1/ai/setup: atomically create application, upstream and access.
// Requires applications:create/update and accesses:create/update plus connector
// visibility. Existing targets return 409; shared configurations are not changed.
message AISetupRequest {
uint64 edge_id = 1;
string service_url = 2; // HTTP(S) API root; no userinfo, query or fragment.
string protocol = 3;
string api_key = 4; // Write-only.
string application_name = 5;
string name = 6;
string description = 7;
map<string,string> models = 8;
}
message AISetupResult {
uint64 id = 1; // New access ID.
uint64 application_id = 2;
}
message AISetupProbeResult {
string state = 1; // compatible, auth_required, unsupported, unknown, unreachable, busy.
repeated string models = 2;
string protocol = 3;
}
// GET/PUT /api/v1/ai/accesses/{id}
message AccessConfig {
bool enabled = 1;
map<string,string> models = 2; // Public alias -> upstream model.
string external_protocol = 3; // Derived from upstream capability, never an arbitrary conversion switch.
}
// GET /api/v1/ai/accesses/{id}/workspace: consumer-safe view, no upstream targets.
message AccessWorkspace {
string name = 1;
bool enabled = 2;
repeated string models = 3;
bool can_manage = 4;
repeated string external_protocols = 5; // Consumer-safe native and implemented conversion protocols; Gemini/Qwen native only.
}
// GET/POST /api/v1/ai/accesses/{id}/keys; DELETE .../keys/{key_id}
message KeyRequest {
string name = 1;
repeated string models = 2;
int32 expires_in_days = 3; // 1..365. No unbounded lifetime.
optional int64 token_limit = 4; // Lifetime input + output, 0..1e12; absent/null = unlimited.
}
message KeyView {
uint64 id = 1;
string name = 2;
repeated string models = 3;
string expires_at = 4;
string secret = 5; // Only in create response; never list.
optional int64 token_limit = 6;
int64 used_tokens = 7; // Reported lifetime usage; never reset on quota changes.
optional int64 remaining_tokens = 8; // null for unlimited OR unknown usage.
int64 unknown_requests = 9;
}
// PUT /api/v1/ai/accesses/{id}/keys/{key_id}/quota
// Requires access update permission AND key ownership. Field must be present;
// explicit null removes the limit. Successful response has data:null.
message UpdateKeyQuotaRequest { optional int64 token_limit = 1; }
// Inference checks before forwarding: 429 TOKEN_QUOTA_EXHAUSTED or
// TOKEN_USAGE_UNCONFIRMED. In-flight requests can exceed the remaining quota;
// this is an admission threshold, NOT hard billing or an output-token cutoff.
// GET /api/v1/ai/accesses/{id}/requests (latest 50 own requests only).
message RequestRecord {
string request_id = 1;
string model = 2;
int32 status = 3;
int64 duration_ms = 4;
optional int64 input_tokens = 5;
optional int64 output_tokens = 6;
bool complete = 7;
uint64 key_id = 8; // Zero for a dashboard-authenticated debug request.
}
// GET /api/v1/ai/accesses/{id}/usage: own usage.
// Optional hours query: 1, 6, 24, 168, 720. Default 720 (rolling 30 days).
// Independent of the 500-request log retention. No historical backfill.
// Missing upstream usage remains null, not measured zero. No billing guarantee.
message TokenUsageRecord {
string request_id = 1;
uint64 key_id = 2; // Zero means authenticated playground.
string model = 3;
optional int64 input_tokens = 4;
optional int64 output_tokens = 5;
bool complete = 6;
string created_at = 7;
}
message TokenUsageSummary {
int64 requests = 1;
int64 unknown_requests = 2;
optional int64 input_tokens = 3; // Sum of reported values only.
optional int64 output_tokens = 4;
}
message TokenUsageResponse {
TokenUsageSummary summary = 1;
repeated TokenUsageRecord records = 2; // Latest 100 within the window.
string since = 3;
}
// SDK endpoints, virtual bearer key only (NOT dashboard JWT/PAT):
// GET /api/v1/ai/accesses/{id}/v1/models
// POST /api/v1/ai/accesses/{id}/v1/chat/completions
// Protocol-native JSON/SSE, no management response envelope. No cookies/CORS.
// POST /api/v1/ai/accesses/{id}/test: authenticated owner's bounded debug request.
// Additional native operations below the access root:
// OpenAI: POST v1/responses (stateless only).
// Ark: POST api/v3/chat/completions and api/v3/responses.
// Qwen: POST api/v1/services/aigc/text-generation/generation;
// X-DashScope-SSE: enable selects SSE; no arbitrary headers forwarded.
// Gemini: POST v1beta/models/{alias}:generateContent or :streamGenerateContent?alt=sse;
// Liaison key in x-goog-api-key or Authorization, never query parameters.
// Ollama: POST api/chat; GET api/tags. No pull/delete/create or arbitrary paths.
// Ollama chat defaults to streaming NDJSON; stream:false returns native JSON.
// Keep-alive/unload, empty-message loading and resource options are not consumer
// capabilities. tags returns authorized aliases only, not upstream model metadata.
// Requests/streams share ownership, model alias, quota, revocation and audit checks.
// Responses previous_response_id/conversation/background and cached/file resource
// references are not exposed without a separate user-scoped ownership registry.