[management,proxy,client] 0.74.0 version (#6563)

* [management,proxy] Agent network: per-account LLM gateway (policy, metering, multi-provider) (#6555)

* [agent-network] Shared proto, OpenAPI schema, and generated types

* [agent-network] Management: store, manager, synthesizer, policy engine, provider catalog, HTTP/gRPC API

Adds the account-scoped agent-network module: provider/policy/budget CRUD and
store, the reverse-proxy service synthesizer, policy selection + limit
enforcement, the provider catalog (incl. Vertex AI and AWS Bedrock entries),
and the management HTTP + proxy gRPC surfaces.

* [management] Fix agent-network proxy-peer fan-out on affected-peer recompute

The affected-peers resolver loaded only persisted reverse-proxy services, but
agent-network services are synthesized on demand and never persisted. As a
result the embedded proxy peer was never folded into the affected set when a
client's group changed, so the proxy received no network-map update for a newly
authorised client and rejected its handshake until a full resync (restart).

loadProxyServices now merges the synthesized agent-network services (injected
via a registration hook to avoid an import cycle), so proxy peers learn newly
authorised clients immediately.

* [proxy] Reverse-proxy middleware framework, chain, and request plumbing

The per-target middleware chain (slots, dispatcher, mutation gate, metadata
merger), body capture, access-log terminal sink, and the proxy wiring that
builds + runs chains for synthesized agent-network services.

* [proxy] LLM parsers, pricing, and builtin middlewares (OpenAI, Anthropic, Vertex AI, AWS Bedrock)

Request/response parsers and SSE/event-stream metering, the embedded pricing
table, and the builtin middleware set: request parser, router, policy
limit-check/record, cost meter, guardrail, identity inject, response parser.
Includes the path-routed providers — Google Vertex AI (keyfile:: service-account
OAuth minting) and AWS Bedrock (bearer auth, invoke/converse/streaming, optional
/bedrock prefix) — plus the Models allowlist and unmeterable-publisher deny.

* [proxy] IPv6 in-place apply and TCP accept-loop hardening on netstack listeners

* [agent-network] End-to-end test suite, module docs, and deployment preset

* [agent-network] Fix codespell typos and exclude false positives

- labelgen word pool: vermillion -> vermilion, racoon -> raccoon.
- codespell ignore list: add flate (Go compress/flate package), recordin
  (a test-local identifier), and unparseable (a valid alternative spelling used
  consistently across identifiers + a metadata-value constant).

* [management] Set LastSeen on injected proxy peer in realstack test (MySQL strict-mode)

The injected embedded proxy peer had a PeerStatus with a zero LastSeen, which
serializes to '0000-00-00' and is rejected by MySQL in strict mode (SQLite
tolerates it). Set LastSeen to a valid time so SaveAccount succeeds on both
engines.

* [agent-network] Remove e2e shell-script suite from this branch

The end-to-end shell scripts under scripts/e2e/ are maintained in a separate
testing suite and are not part of this change set.

* [agent-network] Polish module docs: remove internal review scaffolding, fix links, verify diagrams

Strip PR-review framing, commit references, absolute paths, and stale internal
references from the agent-network module docs; fix broken relative links; verify
all diagrams against the current architecture. Remove the internal AI-reviewer
prompt file.

* [management] Refine session expiration handling to support 3-state encoding for SSO deadlines

* [agent-network] Relocate agentnetwork package to internals/modules

Move management/server/agentnetwork (and its catalog/, labelgen/, types/
subpackages) to management/internals/modules/agentnetwork, alongside the
reverse-proxy module, and rewrite all importers. Pure relocation: package names,
the synthesizer + affectedpeers registration hook, and store access (shared
store.Store) are unchanged, so no import cycle is introduced (affectedpeers
still depends only on the agentnetwork/types leaf).

* [agent-network] Co-locate HTTP handlers in the module (RegisterEndpoints)

Move the agent-network HTTP handlers from server/http/handlers/agentnetwork into
the module at internals/modules/agentnetwork/handlers (package handlers) and
rename the entrypoint AddEndpoints -> RegisterEndpoints, matching the
reverse-proxy module convention. Wiring in http/handler.go updated accordingly.

* Update getting started to point to rc when agent network enabled

* Add a reference to a commercial license

* Fix docs localhost link

* Fix docs localhost link

* Add private services domain note

* [management] Add agent-network telemetry metrics (#6561)

Surface agent-network adoption and usage in the self-hosted metrics
worker: distinct accounts, providers, policies, budget rules, accounts
with log collection enabled, and aggregated input/output tokens plus
cost.

Tokens and cost are summed from agent_network_request_usage (the
always-written per-request ledger) so the figures are accurate
regardless of the log-collection toggle and carry no double-counting.
All values come from a handful of indexed aggregate queries run only on
the worker's periodic tick.

Adds store.AgentNetworkMetrics with GetAgentNetworkMetrics on the Store
interface, the SqlStore implementation, and a zero-valued FileStore stub.

* Update NetBird server and proxy image versions to 0.74.0-rc.2

* [management,proxy] Reduce agent-network cognitive complexity (#6566)

Address the SonarCloud quality-gate findings in new agent-network code
by extracting focused helpers. No behavior change.

- synthesizer.go: split buildIdentityInjectConfigJSON into per-shape
  rule builders; extract mergeGuardrail from mergeGuardrails to cut
  nesting depth.
- llm_identity_inject: extract injectionEmitsAnything validation
  predicate from New.
- llm_response_parser/streaming.go: extract applyOpenAIStreamUsage and
  applyAnthropicStreamUsage (via a named anthropicStreamUsage type) and
  simplify the OpenAI scanner loop.
- reverseproxy.go: decompose ServeHTTP into serveRouteError,
  buildTargetContext, serveDirect, serveWithChain, captureRequestForChain,
  serveDeny, newResponseWriter, observeResponse, and forwardUpstream,
  preserving the defer ordering so response observation still reads the
  captured writer before it is released.

* [management] Move agent-network access-log ingest into the agentnetwork module (#6568)

The agent-network access-log ingest path (metaKey wire contract, flatten,
usage derivation, and the dual-write of the usage ledger + settings-gated
full row) lived in the reverseproxy accesslogs manager, even though the
agentnetwork module already owns the rest of that domain — types, read
(ListAccessLogs / GetUsageOverview), the budget-counter writes, and
retention cleanup.

Move it next to the rest: a stateless agentnetwork.IngestAccessLog(ctx,
store, entry) that the reverseproxy SaveAccessLog delegates to when the
entry is agent-network. Removes the agentNetworkTypes import from the
reverseproxy manager. No behavior change; the write/read table separation
is unchanged.

Adds real-store coverage for the disable->enable log-collection toggle
(usage ledger always written, full row gated) plus the metadata parse and
group-dedup helpers, which previously had no dedicated tests.

* Add session view support in the access log

* [management,proxy] Container-based agent-network e2e harness (#6577)

* [e2e] Add container-based agent-network e2e harness (Pillar 1)

Introduce a self-contained, OIDC-free e2e harness that stands up NetBird
in containers, so suites no longer depend on the hand-maintained Tilt
stack or a real IdP.

- harness brings up the combined server (management + signal + relay +
  STUN + embedded IdP) in a single container built from
  combined/Dockerfile.multistage, and mints an admin PAT through the
  unauthenticated /api/setup bootstrap (NB_SETUP_PAT_ENABLED). API access
  goes through the existing shared/management/client/rest typed client.
- the image is built via the docker CLI (BuildKit) so the Dockerfile's
  cache mounts are honored; testcontainers then runs the tagged image.
- everything is behind the `e2e` build tag so normal builds and unit
  tests never pull in testcontainers.

Adds BuildKit cache mounts to combined/Dockerfile.multistage so source
changes recompile incrementally rather than from scratch.

Pillar 1 proven by TestCombinedBootstrap: server builds, boots, mints a
PAT, and the PAT authenticates a real management API call.

* [e2e] Add management-side agent-network scenarios (Pillar 2)

Port the API-driven agent-network scenarios from the bash suites to Go,
sharing one combined server per package run (TestMain) with each test
owning its resource cleanup. Drives the /api/agent-network/* endpoints
through the shared REST client's NewRequest primitive with the generated
api types.

Scenarios:
- provider lifecycle (create/get/list/delete + 404 after delete)
- provider validation (missing api_key, unknown catalog id → 4xx)
- settings collection-toggle round-trip with cluster/subdomain immutability
- policy window floor (reject <60s enabled limit, accept at 60s)
- consumption read endpoint returns an array

All deterministic and dependency-free (dummy provider keys; no upstream
calls), so they run headless in CI.

* [e2e] Add live chat-through-proxy scenario (Pillar 3)

Stand up the full agent-network data path in containers and drive a real
chat-completion through the gateway:

- harness: a shared docker network (combined server reachable by alias),
  a proxy container built from the published reverse-proxy image
  (NB_PROXY_PRIVATE, NB_PROXY_ALLOW_INSECURE, NB_RELAY_TRANSPORT=ws to match
  the combined server's WS-multiplexed relay) with a generated self-signed
  wildcard cert, and a netbird client container that joins via a setup key.
- the combined image, proxy image, and client image default to the
  published rc.2 releases (overridable via NB_E2E_*_IMAGE; a bare local tag
  is built from source instead). Geolocation download is disabled so the
  server starts without external fetches.
- one shared domain is used for the management exposed address, the proxy
  domain, and the agent-network cluster; the proxy token is minted via the
  server CLI (global) to match the manual install.

TestChatCompletionThroughProxy provisions provider+policy+group+setup key,
runs proxy+client, drives an OpenAI chat-completion through the tunnel, and
asserts a 200 plus the ingested access-log row. Requires OPENAI_TOKEN
(skips otherwise). The provider must be created with enabled=true explicitly
— the create default is false despite the API doc.

* [e2e] Run the live chat scenario across a provider matrix

Replace the single-provider chat test with a data-driven matrix that runs
the same scenario through every provider whose credentials are present in
the environment (keys/URLs sourced from ~/.llm-keys locally, Actions
secrets in CI):

- OpenAI (chat), Anthropic (messages), Vercel, OpenRouter, Cloudflare
  (OpenAI-compatible gateways), and Bedrock (path-routed, bearer, via the
  messages shape) — covering both wire shapes and the gateway routing.
- all providers are created enabled with a unique model string so the
  proxy's connect-time snapshot carries them all and model->provider
  routing is unambiguous (provider toggles after connect don't reconcile
  to a connected proxy).
- the client supports both wire shapes (/v1/chat/completions and
  /v1/messages); Cloudflare gets the openai provider segment appended to
  its gateway URL.

Each provider must return 200 through the tunnel and produce an ingested
access-log row. Vertex is intentionally excluded from the uniform matrix:
it needs a bespoke rawPredict request shape rather than the shared
chat/messages path, so it warrants a dedicated scenario.

* [ci] Add manual workflow for the agent-network e2e suite

The e2e suite (build tag `e2e`) stands up the combined server + proxy +
client in Docker and drives live chat-completions, so it is slow and needs
provider credentials. Gate it out of normal CI (it already is, via the
build tag) and run it on demand via workflow_dispatch. Provider scenarios
skip when their secret is unset, so it degrades gracefully.

* [e2e] Add Vertex to the provider matrix; run e2e on ubuntu-latest

Vertex (Anthropic-on-Vertex) doesn't share the chat/messages wire shapes:
the model travels in a rawPredict path and the proxy mints the service
account's OAuth token. Add a Vertex client method that posts
/v1/projects/<project>/locations/<region>/publishers/anthropic/models/<model>:rawPredict
with the Vertex anthropic_version body, and wire it into the matrix as a
path-routed provider (created without a models array). It is keyed off
GOOGLE_VERTEX_SA_BASE64 + GOOGLE_VERTEX_PROJECT (region defaults to
"global", model to a pinned claude snapshot, both overridable).

Also bump the e2e workflow runner to ubuntu-latest and add the Vertex
secrets.

* Add docker/docker and docker/go-connections as direct dependencies in go.mod

* [ci] Trigger agent-network e2e workflow on push to main and pull requests

* [e2e] Fix proxy cert permission denied on Linux CI runners

The proxy bind-mounts a temp dir of self-signed certs. MkdirTemp creates
it 0700 and the key was 0600, which Docker Desktop on macOS ignores but a
non-root proxy container on Linux runners cannot traverse/read, so the
cert watcher failed with "open /certs/tls.crt: permission denied" and the
container exited. Widen the cert dir to 0755 and write the throwaway key
0644 so the proxy uid can read the bind-mounted material.

* [e2e] Build images from source by default instead of pulling rc.2

The agent-network code under test lives in this branch, so the e2e should
exercise it rather than a frozen published release. Flip the harness
default: combined/proxy/client are now built from their in-repo
Dockerfiles (combined/Dockerfile.multistage, proxy/Dockerfile.multistage,
e2e/harness/Dockerfile.client) under local tags. Pulling a published image
stays available by setting NB_E2E_*_IMAGE to a registry reference.

Builds now go through buildx --load so the Dockerfile cache mounts are
honored and the result is loaded for testcontainers. The CI workflow adds
a container-driver builder and a local layer cache (NB_E2E_BUILDX_CACHE)
persisted via actions/cache, which caches the base/apt/dep-download layers
across runs. The Go compile still re-runs each time, as BuildKit mount
caches cannot be exported to the GitHub cache.

* [e2e] Cover real providers in lifecycle + assert real consumption metering

- TestProviderLifecycle now runs per available real provider (create → get →
  list → delete → 404) instead of a single dummy provider, exercising each
  catalog's create and field round-trip. Create is offline, so it stays fast
  and burns no provider quota; falls back to a synthetic OpenAI provider when
  no keys are set.
- TestProvidersMatrix attaches a token limit (high caps, 60s window) to its
  policy, which switches on usage metering, and asserts consumption rows are
  recorded with positive token counts after the live traffic. Consumption is
  account-scoped (keyed by source group / user and window, not per provider),
  so the assertion is aggregate.
- TestProviderValidation gains invalid-upstream and blank-name cases. Create
  validation is uniform across catalogs (no per-provider required-field rules),
  so per-provider rejection cases would be redundant.

* [e2e] Assert session id propagates per provider

Each matrix request now sends a unique session id as the universal
x-session-id header and asserts it round-trips into that provider's
access-log row. This guards the session-grouping contract end to end for
every provider (header extraction runs in llm_request_parser ahead of the
parser-specific body extraction, so it is provider-agnostic).

* [e2e] Drop accidentally committed sync-phases dashboard

netbird-sync-phases.json was swept into the Pillar 1 commit by a broad
git add; it belongs to the unrelated sync-phases metrics work, not this
e2e harness. Remove it from the branch so the PR diff is scoped to the
e2e changes.

* [e2e] Revert accidentally committed sync-phase ingest spec

The netbird_sync_phase measurement spec in metrics ingest was swept into
the Pillar 1 commit; it belongs to the unrelated sync-phases metrics work,
not this e2e harness. Its emission side never landed here, so the spec was
orphaned anyway. Restore ingest/main.go to its origin/main state.

* Fix golint issues

* Fix sonar

* Add access log session test

* Fix access log tests

---------

Co-authored-by: braginini <bangvalo@gmail.com>
Co-authored-by: Zoltan Papp <zoltan.pmail@gmail.com>
This commit is contained in:
Maycon Santos
2026-07-01 12:45:14 +02:00
committed by GitHub
co-authored by braginini Zoltan Papp
parent 3be90f06b2
commit 92a66cdd20
208 changed files with 39957 additions and 688 deletions
File diff suppressed because it is too large Load Diff
+954
View File
@@ -38,6 +38,45 @@ func (e AccessRestrictionsCrowdsecMode) Valid() bool {
}
}
// Defines values for AgentNetworkCatalogProviderKind.
const (
AgentNetworkCatalogProviderKindCustom AgentNetworkCatalogProviderKind = "custom"
AgentNetworkCatalogProviderKindGateway AgentNetworkCatalogProviderKind = "gateway"
AgentNetworkCatalogProviderKindProvider AgentNetworkCatalogProviderKind = "provider"
)
// Valid indicates whether the value is a known member of the AgentNetworkCatalogProviderKind enum.
func (e AgentNetworkCatalogProviderKind) Valid() bool {
switch e {
case AgentNetworkCatalogProviderKindCustom:
return true
case AgentNetworkCatalogProviderKindGateway:
return true
case AgentNetworkCatalogProviderKindProvider:
return true
default:
return false
}
}
// Defines values for AgentNetworkConsumptionDimensionKind.
const (
AgentNetworkConsumptionDimensionKindGroup AgentNetworkConsumptionDimensionKind = "group"
AgentNetworkConsumptionDimensionKindUser AgentNetworkConsumptionDimensionKind = "user"
)
// Valid indicates whether the value is a known member of the AgentNetworkConsumptionDimensionKind enum.
func (e AgentNetworkConsumptionDimensionKind) Valid() bool {
switch e {
case AgentNetworkConsumptionDimensionKindGroup:
return true
case AgentNetworkConsumptionDimensionKindUser:
return true
default:
return false
}
}
// Defines values for CreateAzureIntegrationRequestHost.
const (
CreateAzureIntegrationRequestHostMicrosoftCom CreateAzureIntegrationRequestHost = "microsoft.com"
@@ -1163,6 +1202,141 @@ func (e WorkloadType) Valid() bool {
}
}
// Defines values for GetApiAgentNetworkAccessLogSessionsParamsSortBy.
const (
GetApiAgentNetworkAccessLogSessionsParamsSortByCostUsd GetApiAgentNetworkAccessLogSessionsParamsSortBy = "cost_usd"
GetApiAgentNetworkAccessLogSessionsParamsSortByDecision GetApiAgentNetworkAccessLogSessionsParamsSortBy = "decision"
GetApiAgentNetworkAccessLogSessionsParamsSortByDuration GetApiAgentNetworkAccessLogSessionsParamsSortBy = "duration"
GetApiAgentNetworkAccessLogSessionsParamsSortByRequestCount GetApiAgentNetworkAccessLogSessionsParamsSortBy = "request_count"
GetApiAgentNetworkAccessLogSessionsParamsSortByStartedAt GetApiAgentNetworkAccessLogSessionsParamsSortBy = "started_at"
GetApiAgentNetworkAccessLogSessionsParamsSortByStatusCode GetApiAgentNetworkAccessLogSessionsParamsSortBy = "status_code"
GetApiAgentNetworkAccessLogSessionsParamsSortByTimestamp GetApiAgentNetworkAccessLogSessionsParamsSortBy = "timestamp"
GetApiAgentNetworkAccessLogSessionsParamsSortByTotalTokens GetApiAgentNetworkAccessLogSessionsParamsSortBy = "total_tokens"
GetApiAgentNetworkAccessLogSessionsParamsSortByUserId GetApiAgentNetworkAccessLogSessionsParamsSortBy = "user_id"
)
// Valid indicates whether the value is a known member of the GetApiAgentNetworkAccessLogSessionsParamsSortBy enum.
func (e GetApiAgentNetworkAccessLogSessionsParamsSortBy) Valid() bool {
switch e {
case GetApiAgentNetworkAccessLogSessionsParamsSortByCostUsd:
return true
case GetApiAgentNetworkAccessLogSessionsParamsSortByDecision:
return true
case GetApiAgentNetworkAccessLogSessionsParamsSortByDuration:
return true
case GetApiAgentNetworkAccessLogSessionsParamsSortByRequestCount:
return true
case GetApiAgentNetworkAccessLogSessionsParamsSortByStartedAt:
return true
case GetApiAgentNetworkAccessLogSessionsParamsSortByStatusCode:
return true
case GetApiAgentNetworkAccessLogSessionsParamsSortByTimestamp:
return true
case GetApiAgentNetworkAccessLogSessionsParamsSortByTotalTokens:
return true
case GetApiAgentNetworkAccessLogSessionsParamsSortByUserId:
return true
default:
return false
}
}
// Defines values for GetApiAgentNetworkAccessLogSessionsParamsSortOrder.
const (
GetApiAgentNetworkAccessLogSessionsParamsSortOrderAsc GetApiAgentNetworkAccessLogSessionsParamsSortOrder = "asc"
GetApiAgentNetworkAccessLogSessionsParamsSortOrderDesc GetApiAgentNetworkAccessLogSessionsParamsSortOrder = "desc"
)
// Valid indicates whether the value is a known member of the GetApiAgentNetworkAccessLogSessionsParamsSortOrder enum.
func (e GetApiAgentNetworkAccessLogSessionsParamsSortOrder) Valid() bool {
switch e {
case GetApiAgentNetworkAccessLogSessionsParamsSortOrderAsc:
return true
case GetApiAgentNetworkAccessLogSessionsParamsSortOrderDesc:
return true
default:
return false
}
}
// Defines values for GetApiAgentNetworkAccessLogsParamsSortBy.
const (
GetApiAgentNetworkAccessLogsParamsSortByCostUsd GetApiAgentNetworkAccessLogsParamsSortBy = "cost_usd"
GetApiAgentNetworkAccessLogsParamsSortByDecision GetApiAgentNetworkAccessLogsParamsSortBy = "decision"
GetApiAgentNetworkAccessLogsParamsSortByDuration GetApiAgentNetworkAccessLogsParamsSortBy = "duration"
GetApiAgentNetworkAccessLogsParamsSortByModel GetApiAgentNetworkAccessLogsParamsSortBy = "model"
GetApiAgentNetworkAccessLogsParamsSortByProvider GetApiAgentNetworkAccessLogsParamsSortBy = "provider"
GetApiAgentNetworkAccessLogsParamsSortByStatusCode GetApiAgentNetworkAccessLogsParamsSortBy = "status_code"
GetApiAgentNetworkAccessLogsParamsSortByTimestamp GetApiAgentNetworkAccessLogsParamsSortBy = "timestamp"
GetApiAgentNetworkAccessLogsParamsSortByTotalTokens GetApiAgentNetworkAccessLogsParamsSortBy = "total_tokens"
GetApiAgentNetworkAccessLogsParamsSortByUserId GetApiAgentNetworkAccessLogsParamsSortBy = "user_id"
)
// Valid indicates whether the value is a known member of the GetApiAgentNetworkAccessLogsParamsSortBy enum.
func (e GetApiAgentNetworkAccessLogsParamsSortBy) Valid() bool {
switch e {
case GetApiAgentNetworkAccessLogsParamsSortByCostUsd:
return true
case GetApiAgentNetworkAccessLogsParamsSortByDecision:
return true
case GetApiAgentNetworkAccessLogsParamsSortByDuration:
return true
case GetApiAgentNetworkAccessLogsParamsSortByModel:
return true
case GetApiAgentNetworkAccessLogsParamsSortByProvider:
return true
case GetApiAgentNetworkAccessLogsParamsSortByStatusCode:
return true
case GetApiAgentNetworkAccessLogsParamsSortByTimestamp:
return true
case GetApiAgentNetworkAccessLogsParamsSortByTotalTokens:
return true
case GetApiAgentNetworkAccessLogsParamsSortByUserId:
return true
default:
return false
}
}
// Defines values for GetApiAgentNetworkAccessLogsParamsSortOrder.
const (
GetApiAgentNetworkAccessLogsParamsSortOrderAsc GetApiAgentNetworkAccessLogsParamsSortOrder = "asc"
GetApiAgentNetworkAccessLogsParamsSortOrderDesc GetApiAgentNetworkAccessLogsParamsSortOrder = "desc"
)
// Valid indicates whether the value is a known member of the GetApiAgentNetworkAccessLogsParamsSortOrder enum.
func (e GetApiAgentNetworkAccessLogsParamsSortOrder) Valid() bool {
switch e {
case GetApiAgentNetworkAccessLogsParamsSortOrderAsc:
return true
case GetApiAgentNetworkAccessLogsParamsSortOrderDesc:
return true
default:
return false
}
}
// Defines values for GetApiAgentNetworkUsageOverviewParamsGranularity.
const (
GetApiAgentNetworkUsageOverviewParamsGranularityDay GetApiAgentNetworkUsageOverviewParamsGranularity = "day"
GetApiAgentNetworkUsageOverviewParamsGranularityMonth GetApiAgentNetworkUsageOverviewParamsGranularity = "month"
GetApiAgentNetworkUsageOverviewParamsGranularityWeek GetApiAgentNetworkUsageOverviewParamsGranularity = "week"
)
// Valid indicates whether the value is a known member of the GetApiAgentNetworkUsageOverviewParamsGranularity enum.
func (e GetApiAgentNetworkUsageOverviewParamsGranularity) Valid() bool {
switch e {
case GetApiAgentNetworkUsageOverviewParamsGranularityDay:
return true
case GetApiAgentNetworkUsageOverviewParamsGranularityMonth:
return true
case GetApiAgentNetworkUsageOverviewParamsGranularityWeek:
return true
default:
return false
}
}
// Defines values for GetApiEventsNetworkTrafficParamsType.
const (
GetApiEventsNetworkTrafficParamsTypeTYPEDROP GetApiEventsNetworkTrafficParamsType = "TYPE_DROP"
@@ -1541,6 +1715,627 @@ type AccountSettings struct {
RoutingPeerDnsResolutionEnabled *bool `json:"routing_peer_dns_resolution_enabled,omitempty"`
}
// AgentNetworkAccessLog One per-request agent-network (LLM) access log entry with flattened, queryable LLM dimensions.
type AgentNetworkAccessLog struct {
// CostUsd Estimated USD cost of the request.
CostUsd float64 `json:"cost_usd"`
// Decision Policy decision for the request (e.g. allow, deny).
Decision *string `json:"decision,omitempty"`
// DenyReason Raw deny reason code when the request was blocked (e.g. llm_policy.token_cap_exceeded).
DenyReason *string `json:"deny_reason,omitempty"`
// DurationMs Duration of the request in milliseconds.
DurationMs int `json:"duration_ms"`
// GroupIds NetBird group ids that authorised the request (the caller's groups intersected with the policy's source groups).
GroupIds *[]string `json:"group_ids,omitempty"`
// Host Upstream host the request was routed to. Empty when log collection is disabled.
Host *string `json:"host,omitempty"`
// Id Unique identifier for the access log entry.
Id string `json:"id"`
// InputTokens Input (prompt) tokens consumed.
InputTokens int64 `json:"input_tokens"`
// Method HTTP method of the request.
Method *string `json:"method,omitempty"`
// Model Requested LLM model.
Model *string `json:"model,omitempty"`
// OutputTokens Output (completion) tokens produced.
OutputTokens int64 `json:"output_tokens"`
// Path Request path. Empty when log collection is disabled.
Path *string `json:"path,omitempty"`
// Provider LLM provider vendor (e.g. openai, anthropic).
Provider *string `json:"provider,omitempty"`
// RequestPrompt Captured request prompt. Present only when prompt collection is enabled.
RequestPrompt *string `json:"request_prompt,omitempty"`
// ResolvedProviderId NetBird agent-network provider id that served the request.
ResolvedProviderId *string `json:"resolved_provider_id,omitempty"`
// ResponseCompletion Captured response completion. Present only when prompt collection is enabled.
ResponseCompletion *string `json:"response_completion,omitempty"`
// SelectedPolicyId Agent-network policy id that authorised (or denied) the request.
SelectedPolicyId *string `json:"selected_policy_id,omitempty"`
// ServiceId ID of the synthesised agent-network service that handled the request.
ServiceId string `json:"service_id"`
// SessionId Conversation / coding-session identifier that groups related requests. Sourced from the client's session marker (e.g. OpenAI Codex client_metadata.session_id, Claude Code metadata.user_id). Empty for clients that send none.
SessionId *string `json:"session_id,omitempty"`
// SourceIp Source IP of the request. Empty when log collection is disabled.
SourceIp *string `json:"source_ip,omitempty"`
// StatusCode HTTP status code returned upstream.
StatusCode int `json:"status_code"`
// Stream Whether the request was a streaming completion.
Stream *bool `json:"stream,omitempty"`
// Timestamp Timestamp when the request was made.
Timestamp time.Time `json:"timestamp"`
// TotalTokens Total tokens consumed.
TotalTokens int64 `json:"total_tokens"`
// UserId NetBird user id of the authenticated caller, if applicable.
UserId *string `json:"user_id,omitempty"`
}
// AgentNetworkAccessLogSession A session-grouped view of agent-network access logs — all requests sharing a session id (or a single session-less request) folded into one summary plus its ordered entries.
type AgentNetworkAccessLogSession struct {
// CostUsd Total estimated USD cost across the session.
CostUsd float64 `json:"cost_usd"`
// Decision Session decision — "deny" if any request was denied, otherwise "allow".
Decision string `json:"decision"`
// EndedAt Timestamp of the session's latest request.
EndedAt time.Time `json:"ended_at"`
// Entries The session's access-log entries, oldest first.
Entries []AgentNetworkAccessLog `json:"entries"`
// GroupIds Union of the authorising group ids across the session's entries.
GroupIds *[]string `json:"group_ids,omitempty"`
// InputTokens Total input (prompt) tokens across the session.
InputTokens int64 `json:"input_tokens"`
// Models Distinct models seen in the session.
Models *[]string `json:"models,omitempty"`
// OutputTokens Total output (completion) tokens across the session.
OutputTokens int64 `json:"output_tokens"`
// Providers Distinct LLM provider vendors seen in the session.
Providers *[]string `json:"providers,omitempty"`
// RequestCount Number of requests in the session.
RequestCount int `json:"request_count"`
// SessionId Conversation / coding-session identifier shared by the entries. Empty for a session-less (singleton) request grouped on its own id.
SessionId *string `json:"session_id,omitempty"`
// StartedAt Timestamp of the session's earliest request.
StartedAt time.Time `json:"started_at"`
// TotalTokens Total tokens across the session.
TotalTokens int64 `json:"total_tokens"`
// UserId NetBird user id of the session's caller.
UserId *string `json:"user_id,omitempty"`
}
// AgentNetworkAccessLogSessionsResponse defines model for AgentNetworkAccessLogSessionsResponse.
type AgentNetworkAccessLogSessionsResponse struct {
// Data List of session-grouped agent-network access logs.
Data []AgentNetworkAccessLogSession `json:"data"`
// Page Current page number.
Page int `json:"page"`
// PageSize Number of sessions per page.
PageSize int `json:"page_size"`
// TotalPages Total number of pages available.
TotalPages int `json:"total_pages"`
// TotalRecords Total number of sessions matching the filter.
TotalRecords int `json:"total_records"`
}
// AgentNetworkAccessLogsResponse defines model for AgentNetworkAccessLogsResponse.
type AgentNetworkAccessLogsResponse struct {
// Data List of agent-network access log entries.
Data []AgentNetworkAccessLog `json:"data"`
// Page Current page number.
Page int `json:"page"`
// PageSize Number of items per page.
PageSize int `json:"page_size"`
// TotalPages Total number of pages available.
TotalPages int `json:"total_pages"`
// TotalRecords Total number of log records matching the filter.
TotalRecords int `json:"total_records"`
}
// AgentNetworkBudgetRule Account-level budget rule. A limit-only rule bound to groups and/or users that applies across all policies as a min-wins ceiling. Empty targets means it applies to every caller.
type AgentNetworkBudgetRule struct {
CreatedAt *time.Time `json:"created_at,omitempty"`
// Enabled Whether the rule is enforced.
Enabled bool `json:"enabled"`
// Id Budget rule ID.
Id string `json:"id"`
// Limits Token and budget caps attached directly to the policy. These compose with any guardrail-level checks.
Limits AgentNetworkPolicyLimits `json:"limits"`
// Name Display name for the budget rule.
Name string `json:"name"`
// TargetGroups NetBird group ids the rule binds. Empty plus empty target_users means account-wide.
TargetGroups []string `json:"target_groups"`
// TargetUsers NetBird user ids the rule binds directly.
TargetUsers []string `json:"target_users"`
UpdatedAt *time.Time `json:"updated_at,omitempty"`
}
// AgentNetworkBudgetRuleRequest defines model for AgentNetworkBudgetRuleRequest.
type AgentNetworkBudgetRuleRequest struct {
// Enabled Whether the rule is enforced. Defaults to true on create.
Enabled *bool `json:"enabled,omitempty"`
// Limits Token and budget caps attached directly to the policy. These compose with any guardrail-level checks.
Limits AgentNetworkPolicyLimits `json:"limits"`
// Name Display name for the budget rule.
Name string `json:"name"`
// TargetGroups NetBird group ids the rule binds. Empty plus empty target_users means account-wide.
TargetGroups *[]string `json:"target_groups,omitempty"`
// TargetUsers NetBird user ids the rule binds directly.
TargetUsers *[]string `json:"target_users,omitempty"`
}
// AgentNetworkCatalogExtraHeader One optional per-provider routing/config header surfaced on the dashboard. Operator-typed value lives on the provider record's `extra_values` map keyed by `name`. UI copy (input label, helper line, tooltip) is owned by the dashboard, keyed by `name`.
type AgentNetworkCatalogExtraHeader struct {
// Name Wire header name the proxy stamps with the operator-typed value.
Name string `json:"name"`
}
// AgentNetworkCatalogHeaderPairInjection HeaderPair identity-injection shape — separate per-dimension headers (LiteLLM-style, Bifrost).
type AgentNetworkCatalogHeaderPairInjection struct {
// Customizable When true, the wire header names are operator-overridable per provider record (Bifrost). When false, the catalog values are authoritative (LiteLLM and similar gateways with a fixed wire protocol).
Customizable bool `json:"customizable"`
// EndUserIdHeader Wire header name for the caller's display identity. Default placeholder when `customizable` is true.
EndUserIdHeader string `json:"end_user_id_header"`
// TagsHeader Wire header name for the caller's groups CSV. Default placeholder when `customizable` is true.
TagsHeader string `json:"tags_header"`
}
// AgentNetworkCatalogIdentityInjection Catalog-declared identity-injection shape. Present when this provider supports stamping the caller's NetBird identity onto upstream requests. Exactly one of `header_pair` or `json_metadata` is set per provider entry. The dashboard reads the `customizable` flag on whichever shape is present to decide whether to surface the labels as editable inputs (true → editable with the catalog values shown as placeholders; false → fixed and read-only).
type AgentNetworkCatalogIdentityInjection struct {
// HeaderPair HeaderPair identity-injection shape — separate per-dimension headers (LiteLLM-style, Bifrost).
HeaderPair *AgentNetworkCatalogHeaderPairInjection `json:"header_pair,omitempty"`
// JsonMetadata JSONMetadata identity-injection shape — one wire header carrying a JSON object whose keys label each dimension (Portkey-style, Cloudflare AI Gateway).
JsonMetadata *AgentNetworkCatalogJSONMetadataInjection `json:"json_metadata,omitempty"`
}
// AgentNetworkCatalogJSONMetadataInjection JSONMetadata identity-injection shape — one wire header carrying a JSON object whose keys label each dimension (Portkey-style, Cloudflare AI Gateway).
type AgentNetworkCatalogJSONMetadataInjection struct {
// Customizable When true, the JSON keys are operator-overridable per provider record (Cloudflare). The wire header itself stays catalog-owned. When false, the catalog values are authoritative (Portkey and similar gateways with a fixed JSON schema).
Customizable bool `json:"customizable"`
// GroupsKey JSON key for the caller's groups CSV. Default placeholder when `customizable` is true.
GroupsKey string `json:"groups_key"`
// Header Wire header name carrying the JSON metadata payload. Catalog-owned (not customizable per provider record).
Header string `json:"header"`
// UserKey JSON key for the caller's display identity. Default placeholder when `customizable` is true.
UserKey string `json:"user_key"`
}
// AgentNetworkCatalogModel defines model for AgentNetworkCatalogModel.
type AgentNetworkCatalogModel struct {
// ContextWindow Maximum context window in tokens.
ContextWindow int `json:"context_window"`
// Id Catalog model identifier as exposed by the upstream provider.
Id string `json:"id"`
// InputPer1k Input token price per 1k tokens, in USD.
InputPer1k float64 `json:"input_per_1k"`
// Label Human-friendly model name for the dashboard.
Label string `json:"label"`
// OutputPer1k Output token price per 1k tokens, in USD.
OutputPer1k float64 `json:"output_per_1k"`
}
// AgentNetworkCatalogProvider defines model for AgentNetworkCatalogProvider.
type AgentNetworkCatalogProvider struct {
// AuthHeaderTemplate Template the proxy uses to inject the API key (the literal string ${API_KEY} is replaced at request time).
AuthHeaderTemplate string `json:"auth_header_template"`
// BrandColor Hex brand color used to render the provider badge in the dashboard.
BrandColor string `json:"brand_color"`
// DefaultContentType Default Content-Type for upstream requests.
DefaultContentType string `json:"default_content_type"`
// DefaultHost Default upstream host suggested when adding a provider of this type.
DefaultHost string `json:"default_host"`
// Description Short description shown in the provider picker.
Description string `json:"description"`
// ExtraHeaders Catalog-declared list of optional per-provider routing/config headers the proxy stamps on every upstream request. Each entry surfaces an input on the dashboard's provider modal (one per item, labeled with `label`). Operators fill any subset; values land on the provider record's `extra_values` map keyed by `name`. Used by gateways like Portkey for `x-portkey-config: pc-...` (saved-config id resolving upstream provider + virtual key).
ExtraHeaders *[]AgentNetworkCatalogExtraHeader `json:"extra_headers,omitempty"`
// Id Catalog provider identifier (referenced by AgentNetworkProvider.provider_id).
Id string `json:"id"`
// IdentityInjection Catalog-declared identity-injection shape. Present when this provider supports stamping the caller's NetBird identity onto upstream requests. Exactly one of `header_pair` or `json_metadata` is set per provider entry. The dashboard reads the `customizable` flag on whichever shape is present to decide whether to surface the labels as editable inputs (true → editable with the catalog values shown as placeholders; false → fixed and read-only).
IdentityInjection *AgentNetworkCatalogIdentityInjection `json:"identity_injection,omitempty"`
// Kind Presentation grouping for the provider Select on the dashboard.
// "provider" — first-party vendor API (OpenAI, Anthropic, …); the upstream is the model itself.
// "gateway" — routing/aggregation layer in front of multiple providers (LiteLLM, Portkey, …); typically pairs with NetBird identity stamping.
// "custom" — generic OpenAI-compatible self-hosted endpoint catch-all.
Kind AgentNetworkCatalogProviderKind `json:"kind"`
// Models Catalog models available for this provider.
Models []AgentNetworkCatalogModel `json:"models"`
// Name Display name for the provider.
Name string `json:"name"`
}
// AgentNetworkCatalogProviderKind Presentation grouping for the provider Select on the dashboard.
// "provider" — first-party vendor API (OpenAI, Anthropic, …); the upstream is the model itself.
// "gateway" — routing/aggregation layer in front of multiple providers (LiteLLM, Portkey, …); typically pairs with NetBird identity stamping.
// "custom" — generic OpenAI-compatible self-hosted endpoint catch-all.
type AgentNetworkCatalogProviderKind string
// AgentNetworkConsumption One per-(dimension, window) consumption counter row. The proxy ticks one row per dimension on every served LLM request; the dashboard reads this listing to surface live counter growth.
type AgentNetworkConsumption struct {
// CostUsd Total USD spend booked against this dimension for the window.
CostUsd float64 `json:"cost_usd"`
// DimensionId NetBird user id (when `dimension_kind=user`) or NetBird group id (when `dimension_kind=group`).
DimensionId string `json:"dimension_id"`
// DimensionKind Whether this row counts a single end user or a single source group across every member.
DimensionKind AgentNetworkConsumptionDimensionKind `json:"dimension_kind"`
// TokensInput Total input tokens consumed within the window.
TokensInput int64 `json:"tokens_input"`
// TokensOutput Total output tokens consumed within the window.
TokensOutput int64 `json:"tokens_output"`
// UpdatedAt Timestamp of the last increment recorded for this row.
UpdatedAt *time.Time `json:"updated_at,omitempty"`
// WindowSeconds Length of the aligned window this counter covers, in seconds. Distinct window lengths produce independent counters even on the same dimension.
WindowSeconds int64 `json:"window_seconds"`
// WindowStartUtc UTC start of the aligned window this counter covers. Aligned to the unix epoch so every node computes the same boundary.
WindowStartUtc time.Time `json:"window_start_utc"`
}
// AgentNetworkConsumptionDimensionKind Whether this row counts a single end user or a single source group across every member.
type AgentNetworkConsumptionDimensionKind string
// AgentNetworkGuardrail defines model for AgentNetworkGuardrail.
type AgentNetworkGuardrail struct {
// Checks Guardrail check parameters. Each entry has an `enabled` flag plus per-check configuration; disabled entries are inert.
Checks AgentNetworkGuardrailChecks `json:"checks"`
// CreatedAt Timestamp when the guardrail was created.
CreatedAt *time.Time `json:"created_at,omitempty"`
// Description Optional human-readable description.
Description string `json:"description"`
// Id Guardrail ID
Id string `json:"id"`
// Name Display name for the guardrail.
Name string `json:"name"`
// UpdatedAt Timestamp when the guardrail was last updated.
UpdatedAt *time.Time `json:"updated_at,omitempty"`
}
// AgentNetworkGuardrailChecks Guardrail check parameters. Each entry has an `enabled` flag plus per-check configuration; disabled entries are inert.
type AgentNetworkGuardrailChecks struct {
ModelAllowlist struct {
Enabled bool `json:"enabled"`
// Models Allowed catalog model ids. Requests for any other model are denied.
Models []string `json:"models"`
} `json:"model_allowlist"`
PromptCapture struct {
Enabled bool `json:"enabled"`
RedactPii bool `json:"redact_pii"`
} `json:"prompt_capture"`
}
// AgentNetworkGuardrailRequest defines model for AgentNetworkGuardrailRequest.
type AgentNetworkGuardrailRequest struct {
// Checks Guardrail check parameters. Each entry has an `enabled` flag plus per-check configuration; disabled entries are inert.
Checks AgentNetworkGuardrailChecks `json:"checks"`
// Description Optional human-readable description.
Description *string `json:"description,omitempty"`
// Name Display name for the guardrail.
Name string `json:"name"`
}
// AgentNetworkPolicy defines model for AgentNetworkPolicy.
type AgentNetworkPolicy struct {
// CreatedAt Timestamp when the policy was created.
CreatedAt *time.Time `json:"created_at,omitempty"`
// Description Optional human-readable description.
Description string `json:"description"`
// DestinationProviderIds Agent Network provider ids (returned by the providers API) the source groups can reach.
DestinationProviderIds []string `json:"destination_provider_ids"`
// Enabled Whether the policy is enabled.
Enabled bool `json:"enabled"`
// GuardrailIds Agent Network guardrail ids attached to this policy.
GuardrailIds []string `json:"guardrail_ids"`
// Id Policy ID
Id string `json:"id"`
// Limits Token and budget caps attached directly to the policy. These compose with any guardrail-level checks.
Limits AgentNetworkPolicyLimits `json:"limits"`
// Name Display name for the policy.
Name string `json:"name"`
// SourceGroups NetBird group ids whose members are allowed to call the destination providers.
SourceGroups []string `json:"source_groups"`
// UpdatedAt Timestamp when the policy was last updated.
UpdatedAt *time.Time `json:"updated_at,omitempty"`
}
// AgentNetworkPolicyBudgetLimit Per-policy USD spend cap. `group_cap_usd` is applied to each source group independently — every group in the policy's `source_groups` gets its own bucket of this size. `user_cap_usd` is applied independently to each individual user. Caps reset to zero at the start of each window.
type AgentNetworkPolicyBudgetLimit struct {
Enabled bool `json:"enabled"`
// GroupCapUsd USD allowed per source group within the window (each group has its own bucket of this size). 0 means uncapped.
GroupCapUsd float64 `json:"group_cap_usd"`
// UserCapUsd USD allowed per individual user within the window. 0 means uncapped.
UserCapUsd float64 `json:"user_cap_usd"`
// WindowSeconds Reset frequency in seconds. Caps reset at the start of each window. Minimum 60 (one minute) when the limit is enabled.
WindowSeconds int64 `json:"window_seconds"`
}
// AgentNetworkPolicyLimits Token and budget caps attached directly to the policy. These compose with any guardrail-level checks.
type AgentNetworkPolicyLimits struct {
// BudgetLimit Per-policy USD spend cap. `group_cap_usd` is applied to each source group independently — every group in the policy's `source_groups` gets its own bucket of this size. `user_cap_usd` is applied independently to each individual user. Caps reset to zero at the start of each window.
BudgetLimit AgentNetworkPolicyBudgetLimit `json:"budget_limit"`
// TokenLimit Per-policy token cap. `group_cap` is applied to each source group independently — every group in the policy's `source_groups` gets its own bucket of this size. `user_cap` is applied independently to each individual user. Caps reset to zero at the start of each window.
TokenLimit AgentNetworkPolicyTokenLimit `json:"token_limit"`
}
// AgentNetworkPolicyRequest defines model for AgentNetworkPolicyRequest.
type AgentNetworkPolicyRequest struct {
// Description Optional human-readable description.
Description *string `json:"description,omitempty"`
// DestinationProviderIds Agent Network provider ids the source groups can reach.
DestinationProviderIds []string `json:"destination_provider_ids"`
// Enabled Whether the policy is enabled. Defaults to true on create.
Enabled *bool `json:"enabled,omitempty"`
// GuardrailIds Agent Network guardrail ids to attach to this policy.
GuardrailIds *[]string `json:"guardrail_ids,omitempty"`
// Limits Token and budget caps attached directly to the policy. These compose with any guardrail-level checks.
Limits *AgentNetworkPolicyLimits `json:"limits,omitempty"`
// Name Display name for the policy.
Name string `json:"name"`
// SourceGroups NetBird group ids whose members are allowed to call the destination providers.
SourceGroups []string `json:"source_groups"`
}
// AgentNetworkPolicyTokenLimit Per-policy token cap. `group_cap` is applied to each source group independently — every group in the policy's `source_groups` gets its own bucket of this size. `user_cap` is applied independently to each individual user. Caps reset to zero at the start of each window.
type AgentNetworkPolicyTokenLimit struct {
Enabled bool `json:"enabled"`
// GroupCap Tokens allowed per source group within the window (each group has its own bucket of this size). 0 means uncapped.
GroupCap int64 `json:"group_cap"`
// UserCap Tokens allowed per individual user within the window. 0 means uncapped.
UserCap int64 `json:"user_cap"`
// WindowSeconds Reset frequency in seconds. The cap counter resets to zero at the start of each window. Minimum 60 (one minute) when the limit is enabled.
WindowSeconds int64 `json:"window_seconds"`
}
// AgentNetworkProvider defines model for AgentNetworkProvider.
type AgentNetworkProvider struct {
// CreatedAt Timestamp when the provider was created.
CreatedAt *time.Time `json:"created_at,omitempty"`
// Enabled Whether the provider is enabled.
Enabled bool `json:"enabled"`
// ExtraValues Operator-typed values for catalog-declared extra headers. Keys are wire header names (e.g. `x-portkey-config`); values are the strings the proxy stamps on every upstream request to this provider. Catalog (AgentNetworkCatalogProvider.extra_headers) declares which keys are accepted; values not declared by the catalog are ignored at synth time. Empty / missing values mean no header stamped.
ExtraValues *map[string]string `json:"extra_values,omitempty"`
// Id Provider ID
Id string `json:"id"`
// IdentityHeaderGroups Wire header name the proxy stamps with the caller's NetBird groups as a comma-separated list (sorted) when the catalog entry's HeaderPair is `customizable`. Empty disables stamping for this dimension. Same per-catalog semantics as `identity_header_user_id`.
IdentityHeaderGroups *string `json:"identity_header_groups,omitempty"`
// IdentityHeaderUserId Wire header name the proxy stamps with the caller's display identity (user email or peer name) when the catalog entry's HeaderPair is `customizable`. Empty disables stamping for this dimension. Ignored when the catalog entry has a fixed HeaderPair (e.g. LiteLLM, Portkey). Used today by Bifrost: typical values are `x-bf-lh-netbird_user_id` (always-on log metadata) or `x-bf-dim-netbird_user_id` (Prometheus / OTEL — requires the label to be pre-declared in the gateway's `client.prometheus_labels` config).
IdentityHeaderUserId *string `json:"identity_header_user_id,omitempty"`
// Models Models exposed through this endpoint, with the operator's per-1k input/output prices. Empty means all catalog models are allowed at catalog prices.
Models []AgentNetworkProviderModel `json:"models"`
// Name Display name shown in the dashboard.
Name string `json:"name"`
// ProviderId Catalog identifier for the upstream AI provider (e.g. openai_api, anthropic_api, azure_openai_api, bedrock_api, vertex_ai_api, mistral_api, custom).
ProviderId string `json:"provider_id"`
// UpdatedAt Timestamp when the provider was last updated.
UpdatedAt *time.Time `json:"updated_at,omitempty"`
// UpstreamUrl Full upstream URL (with scheme) that NetBird forwards traffic to.
UpstreamUrl string `json:"upstream_url"`
}
// AgentNetworkProviderModel A model exposed by the provider, with the operator's per-1k input/output prices in USD.
type AgentNetworkProviderModel struct {
// Id Model identifier (e.g. "gpt-4o-mini").
Id string `json:"id"`
// InputPer1k Cost per 1k input tokens, in USD.
InputPer1k float64 `json:"input_per_1k"`
// OutputPer1k Cost per 1k output tokens, in USD.
OutputPer1k float64 `json:"output_per_1k"`
}
// AgentNetworkProviderRequest defines model for AgentNetworkProviderRequest.
type AgentNetworkProviderRequest struct {
// ApiKey Upstream provider API key. Sealed at rest on the management server and never returned in responses. Required on create; optional on update (omit to keep the existing key).
ApiKey *string `json:"api_key,omitempty"`
// BootstrapCluster Proxy cluster used to bootstrap the per-account agent-network endpoint when the first provider is created. Ignored on subsequent creates and on updates because the cluster is pinned on the account-level Settings row.
BootstrapCluster *string `json:"bootstrap_cluster,omitempty"`
// Enabled Whether the provider is enabled. Defaults to true on create.
Enabled *bool `json:"enabled,omitempty"`
// ExtraValues Operator-typed values for catalog-declared extra headers (see AgentNetworkProvider.extra_values). When present on a request, the whole map replaces the stored values. Empty strings drop the corresponding key.
ExtraValues *map[string]string `json:"extra_values,omitempty"`
// IdentityHeaderGroups Wire header name for the caller's groups CSV. See AgentNetworkProvider.identity_header_groups. Same omit / empty semantics as `identity_header_user_id`.
IdentityHeaderGroups *string `json:"identity_header_groups,omitempty"`
// IdentityHeaderUserId Wire header name for the caller's display identity. See AgentNetworkProvider.identity_header_user_id. When omitted on a request, the stored value is left unchanged; pass an empty string explicitly to clear it (which disables stamping for this dimension).
IdentityHeaderUserId *string `json:"identity_header_user_id,omitempty"`
// Models Models exposed through this endpoint, with the operator's per-1k input/output prices. Empty means all catalog models are allowed at catalog prices.
Models *[]AgentNetworkProviderModel `json:"models,omitempty"`
// Name Display name for the provider.
Name string `json:"name"`
// ProviderId Catalog identifier for the upstream AI provider (e.g. openai_api, anthropic_api, azure_openai_api, bedrock_api, vertex_ai_api, mistral_api, custom).
ProviderId string `json:"provider_id"`
// UpstreamUrl Full upstream URL (with scheme) that NetBird forwards traffic to.
UpstreamUrl string `json:"upstream_url"`
}
// AgentNetworkSettings Per-account Agent Network gateway settings. One row per account; cluster and subdomain are auto-assigned on first provider create and immutable thereafter.
type AgentNetworkSettings struct {
// AccessLogRetentionDays Days to retain full access-log rows; older rows are swept. 0 or less means keep indefinitely. Usage records are retained independently.
AccessLogRetentionDays *int `json:"access_log_retention_days,omitempty"`
// Cluster Address of the NetBird proxy cluster fronting this account's agent-network endpoint.
Cluster string `json:"cluster"`
// CreatedAt Timestamp when the settings row was created.
CreatedAt *time.Time `json:"created_at,omitempty"`
// EnableLogCollection Whether per-request access-log entries are collected for this account's agent-network traffic.
EnableLogCollection bool `json:"enable_log_collection"`
// EnablePromptCollection Master switch for request/response prompt capture. Capture runs only when this is on AND a policy guardrail also enables it.
EnablePromptCollection bool `json:"enable_prompt_collection"`
// Endpoint Bare hostname agents call for this account, computed as `<subdomain>.<cluster>`.
Endpoint string `json:"endpoint"`
// RedactPii Whether captured prompts have PII redacted. Effective redaction is the OR of this and any policy guardrail's redact setting.
RedactPii bool `json:"redact_pii"`
// Subdomain Auto-generated DNS-safe label that prefixes the cluster to form the agent-network endpoint.
Subdomain string `json:"subdomain"`
// UpdatedAt Timestamp when the settings row was last updated.
UpdatedAt *time.Time `json:"updated_at,omitempty"`
}
// AgentNetworkSettingsRequest Mutable account-level Agent Network settings. Cluster and subdomain are immutable and not accepted here.
type AgentNetworkSettingsRequest struct {
// AccessLogRetentionDays Days to retain full access-log rows; older rows are swept. 0 or less means keep indefinitely.
AccessLogRetentionDays *int `json:"access_log_retention_days,omitempty"`
// EnableLogCollection Whether per-request access-log entries are collected for this account's agent-network traffic.
EnableLogCollection bool `json:"enable_log_collection"`
// EnablePromptCollection Master switch for request/response prompt capture.
EnablePromptCollection bool `json:"enable_prompt_collection"`
// RedactPii Whether captured prompts have PII redacted.
RedactPii bool `json:"redact_pii"`
}
// AgentNetworkUsageBucket One aggregated agent-network usage time bucket (UTC). The bucket width is set by the request's granularity.
type AgentNetworkUsageBucket struct {
// CostUsd Total estimated USD spend in the bucket.
CostUsd float64 `json:"cost_usd"`
// InputTokens Total input (prompt) tokens in the bucket.
InputTokens int64 `json:"input_tokens"`
// OutputTokens Total output (completion) tokens in the bucket.
OutputTokens int64 `json:"output_tokens"`
// PeriodStart Start of the bucket in YYYY-MM-DD (UTC) — the day, the week start (Monday), or the month start, depending on granularity.
PeriodStart string `json:"period_start"`
// TotalTokens Total tokens in the bucket.
TotalTokens int64 `json:"total_tokens"`
}
// AvailablePorts defines model for AvailablePorts.
type AvailablePorts struct {
// Tcp Number of available TCP ports left on the ingress peer
@@ -4892,6 +5687,138 @@ type bearerAuthContextKey string
// tokenAuthContextKey is the context key for TokenAuth security scheme
type tokenAuthContextKey string
// GetApiAgentNetworkAccessLogSessionsParams defines parameters for GetApiAgentNetworkAccessLogSessions.
type GetApiAgentNetworkAccessLogSessionsParams struct {
// Page Page number for pagination (1-indexed).
Page *int `form:"page,omitempty" json:"page,omitempty"`
// PageSize Number of sessions per page (max 100).
PageSize *int `form:"page_size,omitempty" json:"page_size,omitempty"`
// SortBy Session-level field to sort by. "timestamp" is the session's last activity, "started_at" its first.
SortBy *GetApiAgentNetworkAccessLogSessionsParamsSortBy `form:"sort_by,omitempty" json:"sort_by,omitempty"`
// SortOrder Sort order (ascending or descending).
SortOrder *GetApiAgentNetworkAccessLogSessionsParamsSortOrder `form:"sort_order,omitempty" json:"sort_order,omitempty"`
// Search General search across log ID, host, path, model, and user email/name.
Search *string `form:"search,omitempty" json:"search,omitempty"`
// UserId Filter by authenticated user ID.
UserId *string `form:"user_id,omitempty" json:"user_id,omitempty"`
// SessionId Filter to a single conversation / coding session id.
SessionId *string `form:"session_id,omitempty" json:"session_id,omitempty"`
// GroupId Filter by authorising group id. Repeat for multiple (matches any).
GroupId *[]string `form:"group_id,omitempty" json:"group_id,omitempty"`
// ProviderId Filter by resolved provider id. Repeat for multiple (matches any).
ProviderId *[]string `form:"provider_id,omitempty" json:"provider_id,omitempty"`
// Model Filter by model. Repeat for multiple (matches any).
Model *[]string `form:"model,omitempty" json:"model,omitempty"`
// Decision Filter by policy decision (e.g. allow, deny).
Decision *string `form:"decision,omitempty" json:"decision,omitempty"`
// Path Filter by request path prefix (matches entries whose path starts with this value).
Path *string `form:"path,omitempty" json:"path,omitempty"`
// StartDate Filter by timestamp >= start_date (RFC3339 format).
StartDate *time.Time `form:"start_date,omitempty" json:"start_date,omitempty"`
// EndDate Filter by timestamp <= end_date (RFC3339 format).
EndDate *time.Time `form:"end_date,omitempty" json:"end_date,omitempty"`
}
// GetApiAgentNetworkAccessLogSessionsParamsSortBy defines parameters for GetApiAgentNetworkAccessLogSessions.
type GetApiAgentNetworkAccessLogSessionsParamsSortBy string
// GetApiAgentNetworkAccessLogSessionsParamsSortOrder defines parameters for GetApiAgentNetworkAccessLogSessions.
type GetApiAgentNetworkAccessLogSessionsParamsSortOrder string
// GetApiAgentNetworkAccessLogsParams defines parameters for GetApiAgentNetworkAccessLogs.
type GetApiAgentNetworkAccessLogsParams struct {
// Page Page number for pagination (1-indexed).
Page *int `form:"page,omitempty" json:"page,omitempty"`
// PageSize Number of items per page (max 100).
PageSize *int `form:"page_size,omitempty" json:"page_size,omitempty"`
// SortBy Field to sort by.
SortBy *GetApiAgentNetworkAccessLogsParamsSortBy `form:"sort_by,omitempty" json:"sort_by,omitempty"`
// SortOrder Sort order (ascending or descending).
SortOrder *GetApiAgentNetworkAccessLogsParamsSortOrder `form:"sort_order,omitempty" json:"sort_order,omitempty"`
// Search General search across log ID, host, path, model, and user email/name.
Search *string `form:"search,omitempty" json:"search,omitempty"`
// UserId Filter by authenticated user ID.
UserId *string `form:"user_id,omitempty" json:"user_id,omitempty"`
// SessionId Filter to a single conversation / coding session id (groups all requests of one session).
SessionId *string `form:"session_id,omitempty" json:"session_id,omitempty"`
// GroupId Filter by authorising group id. Repeat for multiple (matches any).
GroupId *[]string `form:"group_id,omitempty" json:"group_id,omitempty"`
// ProviderId Filter by resolved provider id. Repeat for multiple (matches any).
ProviderId *[]string `form:"provider_id,omitempty" json:"provider_id,omitempty"`
// Model Filter by model. Repeat for multiple (matches any).
Model *[]string `form:"model,omitempty" json:"model,omitempty"`
// Decision Filter by policy decision (e.g. allow, deny).
Decision *string `form:"decision,omitempty" json:"decision,omitempty"`
// Path Filter by request path prefix (matches entries whose path starts with this value).
Path *string `form:"path,omitempty" json:"path,omitempty"`
// StartDate Filter by timestamp >= start_date (RFC3339 format).
StartDate *time.Time `form:"start_date,omitempty" json:"start_date,omitempty"`
// EndDate Filter by timestamp <= end_date (RFC3339 format).
EndDate *time.Time `form:"end_date,omitempty" json:"end_date,omitempty"`
}
// GetApiAgentNetworkAccessLogsParamsSortBy defines parameters for GetApiAgentNetworkAccessLogs.
type GetApiAgentNetworkAccessLogsParamsSortBy string
// GetApiAgentNetworkAccessLogsParamsSortOrder defines parameters for GetApiAgentNetworkAccessLogs.
type GetApiAgentNetworkAccessLogsParamsSortOrder string
// GetApiAgentNetworkUsageOverviewParams defines parameters for GetApiAgentNetworkUsageOverview.
type GetApiAgentNetworkUsageOverviewParams struct {
// Granularity Time bucket width. Defaults to day.
Granularity *GetApiAgentNetworkUsageOverviewParamsGranularity `form:"granularity,omitempty" json:"granularity,omitempty"`
// StartDate Filter by timestamp >= start_date (RFC3339 format).
StartDate *time.Time `form:"start_date,omitempty" json:"start_date,omitempty"`
// EndDate Filter by timestamp <= end_date (RFC3339 format).
EndDate *time.Time `form:"end_date,omitempty" json:"end_date,omitempty"`
// UserId Filter by user ID.
UserId *string `form:"user_id,omitempty" json:"user_id,omitempty"`
// SessionId Filter to a single conversation / coding session id.
SessionId *string `form:"session_id,omitempty" json:"session_id,omitempty"`
// GroupId Filter by authorising group id. Repeat for multiple (matches any).
GroupId *[]string `form:"group_id,omitempty" json:"group_id,omitempty"`
// ProviderId Filter by resolved provider id. Repeat for multiple (matches any).
ProviderId *[]string `form:"provider_id,omitempty" json:"provider_id,omitempty"`
// Model Filter by model. Repeat for multiple (matches any).
Model *[]string `form:"model,omitempty" json:"model,omitempty"`
}
// GetApiAgentNetworkUsageOverviewParamsGranularity defines parameters for GetApiAgentNetworkUsageOverview.
type GetApiAgentNetworkUsageOverviewParamsGranularity string
// GetApiEventsNetworkTrafficParams defines parameters for GetApiEventsNetworkTraffic.
type GetApiEventsNetworkTrafficParams struct {
// Page Page number
@@ -5090,6 +6017,33 @@ type GetApiUsersParams struct {
// PutApiAccountsAccountIdJSONRequestBody defines body for PutApiAccountsAccountId for application/json ContentType.
type PutApiAccountsAccountIdJSONRequestBody = AccountRequest
// PostApiAgentNetworkBudgetRulesJSONRequestBody defines body for PostApiAgentNetworkBudgetRules for application/json ContentType.
type PostApiAgentNetworkBudgetRulesJSONRequestBody = AgentNetworkBudgetRuleRequest
// PutApiAgentNetworkBudgetRulesRuleIdJSONRequestBody defines body for PutApiAgentNetworkBudgetRulesRuleId for application/json ContentType.
type PutApiAgentNetworkBudgetRulesRuleIdJSONRequestBody = AgentNetworkBudgetRuleRequest
// PostApiAgentNetworkGuardrailsJSONRequestBody defines body for PostApiAgentNetworkGuardrails for application/json ContentType.
type PostApiAgentNetworkGuardrailsJSONRequestBody = AgentNetworkGuardrailRequest
// PutApiAgentNetworkGuardrailsGuardrailIdJSONRequestBody defines body for PutApiAgentNetworkGuardrailsGuardrailId for application/json ContentType.
type PutApiAgentNetworkGuardrailsGuardrailIdJSONRequestBody = AgentNetworkGuardrailRequest
// PostApiAgentNetworkPoliciesJSONRequestBody defines body for PostApiAgentNetworkPolicies for application/json ContentType.
type PostApiAgentNetworkPoliciesJSONRequestBody = AgentNetworkPolicyRequest
// PutApiAgentNetworkPoliciesPolicyIdJSONRequestBody defines body for PutApiAgentNetworkPoliciesPolicyId for application/json ContentType.
type PutApiAgentNetworkPoliciesPolicyIdJSONRequestBody = AgentNetworkPolicyRequest
// PostApiAgentNetworkProvidersJSONRequestBody defines body for PostApiAgentNetworkProviders for application/json ContentType.
type PostApiAgentNetworkProvidersJSONRequestBody = AgentNetworkProviderRequest
// PutApiAgentNetworkProvidersProviderIdJSONRequestBody defines body for PutApiAgentNetworkProvidersProviderId for application/json ContentType.
type PutApiAgentNetworkProvidersProviderIdJSONRequestBody = AgentNetworkProviderRequest
// PutApiAgentNetworkSettingsJSONRequestBody defines body for PutApiAgentNetworkSettings for application/json ContentType.
type PutApiAgentNetworkSettingsJSONRequestBody = AgentNetworkSettingsRequest
// PostApiDnsNameserversJSONRequestBody defines body for PostApiDnsNameservers for application/json ContentType.
type PostApiDnsNameserversJSONRequestBody = NameserverGroupRequest
+17 -7
View File
@@ -843,10 +843,14 @@ type SyncResponse struct {
NetworkMap *NetworkMap `protobuf:"bytes,5,opt,name=NetworkMap,proto3" json:"NetworkMap,omitempty"`
// Posture checks to be evaluated by client
Checks []*Checks `protobuf:"bytes,6,rep,name=Checks,proto3" json:"Checks,omitempty"`
// Absolute UTC instant at which the peer's SSO session expires.
// Unset when the peer is not SSO-registered or login expiration is disabled.
// Carried on every Sync snapshot so admin-side changes propagate live without
// a client reconnect.
// 3-state session deadline. Carried on every Sync snapshot so admin-side
// changes propagate live without a client reconnect.
//
// field unset (nil) → snapshot carries no info; client keeps the
// deadline it already had
// set, seconds=0 nanos=0 → explicit "expiry disabled" or peer is not
// SSO-registered; client clears its anchor
// set, valid timestamp → new absolute UTC deadline
SessionExpiresAt *timestamppb.Timestamp `protobuf:"bytes,7,opt,name=sessionExpiresAt,proto3" json:"sessionExpiresAt,omitempty"`
}
@@ -1608,8 +1612,11 @@ type LoginResponse struct {
PeerConfig *PeerConfig `protobuf:"bytes,2,opt,name=peerConfig,proto3" json:"peerConfig,omitempty"`
// Posture checks to be evaluated by client
Checks []*Checks `protobuf:"bytes,3,rep,name=Checks,proto3" json:"Checks,omitempty"`
// Absolute UTC instant at which the peer's SSO session expires.
// Unset when the peer is not SSO-registered or login expiration is disabled.
// 3-state session deadline; same encoding as SyncResponse.sessionExpiresAt.
//
// field unset (nil) → no info; client keeps any deadline it had
// set, seconds=0 nanos=0 → explicit "expiry disabled" / non-SSO peer
// set, valid timestamp → new absolute UTC deadline
SessionExpiresAt *timestamppb.Timestamp `protobuf:"bytes,4,opt,name=sessionExpiresAt,proto3" json:"sessionExpiresAt,omitempty"`
}
@@ -1739,7 +1746,10 @@ type ExtendAuthSessionResponse struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// Absolute UTC instant at which the peer's SSO session now expires.
// 3-state session deadline; same encoding as SyncResponse.sessionExpiresAt.
// In practice ExtendAuthSession only succeeds for SSO peers with expiry
// enabled, so this carries a valid timestamp on the success path. The
// 3-state encoding is documented here for symmetry with Login/Sync.
SessionExpiresAt *timestamppb.Timestamp `protobuf:"bytes,1,opt,name=sessionExpiresAt,proto3" json:"sessionExpiresAt,omitempty"`
}
File diff suppressed because it is too large Load Diff
+125
View File
@@ -43,6 +43,18 @@ service ProxyService {
// issue a session cookie without redirecting through the OIDC flow.
// Mirrors ValidateSession's response shape.
rpc ValidateTunnelPeer(ValidateTunnelPeerRequest) returns (ValidateTunnelPeerResponse);
// CheckLLMPolicyLimits is the pre-flight RPC the proxy calls before each
// LLM request. Management runs the per-policy headroom selection across
// every policy authorising the caller's user / groups for the resolved
// provider and returns the chosen attribution policy + group, or a deny
// when no applicable policy has headroom > 0.
rpc CheckLLMPolicyLimits(CheckLLMPolicyLimitsRequest) returns (CheckLLMPolicyLimitsResponse);
// RecordLLMUsage is the post-flight RPC the proxy calls after the upstream
// returns. Increments the per-(dimension, window) counters for the
// attribution policy chosen by CheckLLMPolicyLimits.
rpc RecordLLMUsage(RecordLLMUsageRequest) returns (RecordLLMUsageResponse);
}
// ProxyCapabilities describes what a proxy can handle.
@@ -107,6 +119,59 @@ message PathTargetOptions {
// reachable without WireGuard (public APIs, LAN services, localhost
// sidecars). Defaults to false — embedded client is the standard path.
bool direct_upstream = 7;
// Proxy clamps to [0, proxy-wide max (1 MiB)] at apply time. Agent-network
// synthesized targets only; private services leave these zero.
int64 capture_max_request_bytes = 8;
// Proxy clamps to [0, proxy-wide max (1 MiB)] at apply time.
int64 capture_max_response_bytes = 9;
// Content types eligible for body capture (e.g. "application/json").
repeated string capture_content_types = 10;
// Per-target middleware configurations populated by the agent-network
// synthesizer. Validated and clamped by the proxy at apply time.
repeated MiddlewareConfig middlewares = 11;
// When true, the proxy stamps agent_network=true on access-log entries
// for this target so management routes them to the agent-network log
// surface.
bool agent_network = 12;
// When true, the proxy suppresses the per-request access-log emission for
// this target. Defaults false to preserve existing access-log behavior for
// every non-agent-network target. The agent-network synth target sets this
// true only when the account's EnableLogCollection toggle is off.
bool disable_access_log = 13;
}
// MiddlewareSlot identifies where in the request lifecycle a middleware
// runs. Mirrors proxy/internal/middleware.Slot.
enum MiddlewareSlot {
MIDDLEWARE_SLOT_UNSPECIFIED = 0;
MIDDLEWARE_SLOT_ON_REQUEST = 1;
MIDDLEWARE_SLOT_ON_RESPONSE = 2;
MIDDLEWARE_SLOT_TERMINAL = 3;
}
// MiddlewareConfig is the per-target configuration for a single middleware.
// The proxy validates every incoming MiddlewareConfig at apply time:
// unknown ids are rejected, timeout is clamped to [10ms, 5s], and the
// declared slot must match the registered middleware's slot.
message MiddlewareConfig {
// Middleware id; must match the proxy-local compiled-in registry.
string id = 1;
bool enabled = 2;
MiddlewareSlot slot = 3;
// Free-form JSON unmarshalled by the middleware factory into its own typed
// config struct. Empty / null / {} are valid (zero-value config).
bytes config_json = 4;
enum FailMode {
FAIL_OPEN = 0;
FAIL_CLOSED = 1;
}
FailMode fail_mode = 5;
// Clamped to [10ms, 5s] at apply time; zero → 500ms default.
google.protobuf.Duration timeout = 6;
// When true, the middleware may mutate request headers or body (subject to
// policy). Honoured only when the implementation also declares
// MutationsSupported.
bool can_mutate = 7;
}
message PathMapping {
@@ -190,6 +255,10 @@ message AccessLog {
string protocol = 16;
// Extra key-value metadata for the access log entry (e.g. crowdsec_verdict, scenario).
map<string, string> metadata = 17;
// When true, the entry was emitted by an agent-network synth service.
// Management routes these to the agent-network access-log surface instead
// of the standard service log.
bool agent_network = 18;
}
message AuthenticateRequest {
@@ -376,3 +445,59 @@ message SyncMappingsResponse {
bool initial_sync_complete = 2;
}
// CheckLLMPolicyLimitsRequest carries the resolved caller identity and the
// upstream provider already chosen by llm_router. Management computes which
// policies authorise the request, picks the one with the most remaining
// headroom, and returns the attribution decision.
message CheckLLMPolicyLimitsRequest {
// account_id is the netbird account the request belongs to.
string account_id = 1;
// user_id is the netbird user id of the caller. May be empty when the
// principal is a tunnel-peer that isn't bound to a user; group membership
// still gates the request in that case.
string user_id = 2;
// group_ids is the caller's full group membership at request time.
repeated string group_ids = 3;
// provider_id is the agent-network provider record id chosen by llm_router.
string provider_id = 4;
// model is the upstream model identifier extracted from the request body.
string model = 5;
}
// CheckLLMPolicyLimitsResponse is management's allow-or-deny decision for a
// pre-flight check.
message CheckLLMPolicyLimitsResponse {
// decision is "allow" or "deny".
string decision = 1;
// selected_policy_id names the policy that paid for this request.
string selected_policy_id = 2;
// attribution_group_id is the source group the request booked against.
string attribution_group_id = 3;
// window_seconds is the cap window length the selected policy uses.
int64 window_seconds = 4;
// deny_code is set on decision="deny" with a stable label.
string deny_code = 5;
// deny_reason is a short human-readable explanation paired with deny_code.
string deny_reason = 6;
}
// RecordLLMUsageRequest is the post-flight increment the proxy posts after
// the upstream call. Counters are keyed on (account, dimension, window).
message RecordLLMUsageRequest {
string account_id = 1;
string user_id = 2;
// group_id is the selected policy's attribution group, recorded against the
// policy window (window_seconds).
string group_id = 3;
int64 window_seconds = 4;
int64 tokens_input = 5;
int64 tokens_output = 6;
double cost_usd = 7;
// group_ids is the caller's full group membership, used to fan the same
// usage out to every applicable account-level budget rule's own window.
repeated string group_ids = 8;
}
message RecordLLMUsageResponse {
}
@@ -43,6 +43,16 @@ type ProxyServiceClient interface {
// issue a session cookie without redirecting through the OIDC flow.
// Mirrors ValidateSession's response shape.
ValidateTunnelPeer(ctx context.Context, in *ValidateTunnelPeerRequest, opts ...grpc.CallOption) (*ValidateTunnelPeerResponse, error)
// CheckLLMPolicyLimits is the pre-flight RPC the proxy calls before each
// LLM request. Management runs the per-policy headroom selection across
// every policy authorising the caller's user / groups for the resolved
// provider and returns the chosen attribution policy + group, or a deny
// when no applicable policy has headroom > 0.
CheckLLMPolicyLimits(ctx context.Context, in *CheckLLMPolicyLimitsRequest, opts ...grpc.CallOption) (*CheckLLMPolicyLimitsResponse, error)
// RecordLLMUsage is the post-flight RPC the proxy calls after the upstream
// returns. Increments the per-(dimension, window) counters for the
// attribution policy chosen by CheckLLMPolicyLimits.
RecordLLMUsage(ctx context.Context, in *RecordLLMUsageRequest, opts ...grpc.CallOption) (*RecordLLMUsageResponse, error)
}
type proxyServiceClient struct {
@@ -179,6 +189,24 @@ func (c *proxyServiceClient) ValidateTunnelPeer(ctx context.Context, in *Validat
return out, nil
}
func (c *proxyServiceClient) CheckLLMPolicyLimits(ctx context.Context, in *CheckLLMPolicyLimitsRequest, opts ...grpc.CallOption) (*CheckLLMPolicyLimitsResponse, error) {
out := new(CheckLLMPolicyLimitsResponse)
err := c.cc.Invoke(ctx, "/management.ProxyService/CheckLLMPolicyLimits", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *proxyServiceClient) RecordLLMUsage(ctx context.Context, in *RecordLLMUsageRequest, opts ...grpc.CallOption) (*RecordLLMUsageResponse, error) {
out := new(RecordLLMUsageResponse)
err := c.cc.Invoke(ctx, "/management.ProxyService/RecordLLMUsage", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// ProxyServiceServer is the server API for ProxyService service.
// All implementations must embed UnimplementedProxyServiceServer
// for forward compatibility
@@ -208,6 +236,16 @@ type ProxyServiceServer interface {
// issue a session cookie without redirecting through the OIDC flow.
// Mirrors ValidateSession's response shape.
ValidateTunnelPeer(context.Context, *ValidateTunnelPeerRequest) (*ValidateTunnelPeerResponse, error)
// CheckLLMPolicyLimits is the pre-flight RPC the proxy calls before each
// LLM request. Management runs the per-policy headroom selection across
// every policy authorising the caller's user / groups for the resolved
// provider and returns the chosen attribution policy + group, or a deny
// when no applicable policy has headroom > 0.
CheckLLMPolicyLimits(context.Context, *CheckLLMPolicyLimitsRequest) (*CheckLLMPolicyLimitsResponse, error)
// RecordLLMUsage is the post-flight RPC the proxy calls after the upstream
// returns. Increments the per-(dimension, window) counters for the
// attribution policy chosen by CheckLLMPolicyLimits.
RecordLLMUsage(context.Context, *RecordLLMUsageRequest) (*RecordLLMUsageResponse, error)
mustEmbedUnimplementedProxyServiceServer()
}
@@ -242,6 +280,12 @@ func (UnimplementedProxyServiceServer) ValidateSession(context.Context, *Validat
func (UnimplementedProxyServiceServer) ValidateTunnelPeer(context.Context, *ValidateTunnelPeerRequest) (*ValidateTunnelPeerResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method ValidateTunnelPeer not implemented")
}
func (UnimplementedProxyServiceServer) CheckLLMPolicyLimits(context.Context, *CheckLLMPolicyLimitsRequest) (*CheckLLMPolicyLimitsResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method CheckLLMPolicyLimits not implemented")
}
func (UnimplementedProxyServiceServer) RecordLLMUsage(context.Context, *RecordLLMUsageRequest) (*RecordLLMUsageResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method RecordLLMUsage not implemented")
}
func (UnimplementedProxyServiceServer) mustEmbedUnimplementedProxyServiceServer() {}
// UnsafeProxyServiceServer may be embedded to opt out of forward compatibility for this service.
@@ -428,6 +472,42 @@ func _ProxyService_ValidateTunnelPeer_Handler(srv interface{}, ctx context.Conte
return interceptor(ctx, in, info, handler)
}
func _ProxyService_CheckLLMPolicyLimits_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(CheckLLMPolicyLimitsRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ProxyServiceServer).CheckLLMPolicyLimits(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/management.ProxyService/CheckLLMPolicyLimits",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ProxyServiceServer).CheckLLMPolicyLimits(ctx, req.(*CheckLLMPolicyLimitsRequest))
}
return interceptor(ctx, in, info, handler)
}
func _ProxyService_RecordLLMUsage_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(RecordLLMUsageRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ProxyServiceServer).RecordLLMUsage(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/management.ProxyService/RecordLLMUsage",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ProxyServiceServer).RecordLLMUsage(ctx, req.(*RecordLLMUsageRequest))
}
return interceptor(ctx, in, info, handler)
}
// ProxyService_ServiceDesc is the grpc.ServiceDesc for ProxyService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
@@ -463,6 +543,14 @@ var ProxyService_ServiceDesc = grpc.ServiceDesc{
MethodName: "ValidateTunnelPeer",
Handler: _ProxyService_ValidateTunnelPeer_Handler,
},
{
MethodName: "CheckLLMPolicyLimits",
Handler: _ProxyService_CheckLLMPolicyLimits_Handler,
},
{
MethodName: "RecordLLMUsage",
Handler: _ProxyService_RecordLLMUsage_Handler,
},
},
Streams: []grpc.StreamDesc{
{
+20
View File
@@ -219,6 +219,26 @@ func NewNetworkResourceNotFoundError(resourceID string) error {
return Errorf(NotFound, "network resource: %s not found", resourceID)
}
// NewAgentNetworkProviderNotFoundError creates a new Error with NotFound type for a missing Agent Network provider.
func NewAgentNetworkProviderNotFoundError(providerID string) error {
return Errorf(NotFound, "agent network provider: %s not found", providerID)
}
// NewAgentNetworkPolicyNotFoundError creates a new Error with NotFound type for a missing Agent Network policy.
func NewAgentNetworkPolicyNotFoundError(policyID string) error {
return Errorf(NotFound, "agent network policy: %s not found", policyID)
}
// NewAgentNetworkGuardrailNotFoundError creates a new Error with NotFound type for a missing Agent Network guardrail.
func NewAgentNetworkGuardrailNotFoundError(guardrailID string) error {
return Errorf(NotFound, "agent network guardrail: %s not found", guardrailID)
}
// NewAgentNetworkBudgetRuleNotFoundError creates a new Error with NotFound type for a missing Agent Network budget rule.
func NewAgentNetworkBudgetRuleNotFoundError(ruleID string) error {
return Errorf(NotFound, "agent network budget rule: %s not found", ruleID)
}
// NewPermissionDeniedError creates a new Error with PermissionDenied type for a permission denied error.
func NewPermissionDeniedError() error {
return Errorf(PermissionDenied, "permission denied")