109 lines
4.1 KiB
Python
109 lines
4.1 KiB
Python
"""Configuration for the third-party API proxy with billing integration."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from pydantic import BaseModel, Field
|
|
|
|
|
|
class SubmitRouteConfig(BaseModel):
|
|
"""Identifies a submit request — triggers billing reserve + task state tracking."""
|
|
|
|
method: str = Field(default="POST", description="HTTP method to match (case-insensitive)")
|
|
path_pattern: str = Field(
|
|
description="Glob-style path pattern. Use ** to match any sub-path, e.g. /openapi/v2/**"
|
|
)
|
|
exclude_path_pattern: str | None = Field(
|
|
default=None,
|
|
description="If set, paths matching this pattern are excluded from submit handling",
|
|
)
|
|
task_id_jsonpath: str = Field(
|
|
description="Dot-path into the *response* body to extract the provider task ID, e.g. taskId"
|
|
)
|
|
frozen_amount: float | None = Field(
|
|
default=None,
|
|
ge=0,
|
|
description="Optional route-level override for billing reserve payload frozenAmount",
|
|
)
|
|
frozen_type: int | None = Field(
|
|
default=None,
|
|
description="Optional route-level override for billing reserve payload frozenType",
|
|
)
|
|
|
|
|
|
class QueryRouteConfig(BaseModel):
|
|
"""Identifies a query/poll request — checks for terminal status + triggers billing finalize."""
|
|
|
|
method: str = Field(default="POST", description="HTTP method to match (case-insensitive)")
|
|
path_pattern: str = Field(description="Glob-style path pattern for the query endpoint")
|
|
request_task_id_jsonpath: str = Field(
|
|
description="Dot-path into the *request* body to extract the task ID being queried"
|
|
)
|
|
status_jsonpath: str = Field(
|
|
description="Dot-path into the response body to read the task status value"
|
|
)
|
|
success_values: list[str] = Field(
|
|
default_factory=list,
|
|
description="Status string values that indicate successful terminal state, e.g. [\"SUCCESS\"]",
|
|
)
|
|
failure_values: list[str] = Field(
|
|
default_factory=list,
|
|
description="Status string values that indicate failed terminal state, e.g. [\"FAILED\", \"CANCELLED\"]",
|
|
)
|
|
usage_jsonpath: str | None = Field(
|
|
default=None,
|
|
description=(
|
|
"Dot-path into the response body for the actual monetary cost to pass to billing finalize. "
|
|
"E.g. usage.thirdPartyConsumeMoney"
|
|
),
|
|
)
|
|
|
|
|
|
class ThirdPartyProviderConfig(BaseModel):
|
|
"""Configuration for a single third-party API platform."""
|
|
|
|
base_url: str = Field(description="Base URL of the provider, e.g. https://www.runninghub.cn")
|
|
api_key_env: str | None = Field(
|
|
default=None,
|
|
description="Name of the environment variable holding the API key",
|
|
)
|
|
api_key_header: str = Field(
|
|
default="Authorization",
|
|
description="Request header name for the API key",
|
|
)
|
|
api_key_prefix: str = Field(
|
|
default="Bearer ",
|
|
description="String prepended to the API key value in the header",
|
|
)
|
|
timeout_seconds: float = Field(
|
|
default=30.0,
|
|
gt=0,
|
|
description="HTTP request timeout when forwarding to the provider",
|
|
)
|
|
frozen_amount: float = Field(
|
|
default=0.0,
|
|
ge=0,
|
|
description="Amount to reserve in billing reserve payload (frozenAmount)",
|
|
)
|
|
frozen_type: int | None = Field(
|
|
default=None,
|
|
description="Billing frozen type for this provider (frozenType). If omitted, falls back to billing.frozen_type",
|
|
)
|
|
submit_routes: list[SubmitRouteConfig] = Field(
|
|
default_factory=list,
|
|
description="Route patterns that identify submit (task-create) requests",
|
|
)
|
|
query_routes: list[QueryRouteConfig] = Field(
|
|
default_factory=list,
|
|
description="Route patterns that identify query/poll requests",
|
|
)
|
|
|
|
|
|
class ThirdPartyProxyConfig(BaseModel):
|
|
"""Top-level configuration for the third-party API proxy."""
|
|
|
|
enabled: bool = Field(default=False, description="Enable the proxy endpoint")
|
|
providers: dict[str, ThirdPartyProviderConfig] = Field(
|
|
default_factory=dict,
|
|
description="Keyed by provider name (used in the URL path /api/proxy/{provider}/...)",
|
|
)
|