refactor(api): scope uv to s2s-client and validate compatible responses
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
from pydantic import BaseModel, ConfigDict
|
||||
|
||||
|
||||
class SearchRequest(BaseModel):
|
||||
query: str
|
||||
# Optional user-supplied key (fallback when the deploy has no server key).
|
||||
# Used for this request only; never stored.
|
||||
key: str | None = None
|
||||
|
||||
|
||||
class ReasoningRequest(BaseModel):
|
||||
transcript: str
|
||||
instructions: str = ""
|
||||
language: str = ""
|
||||
user_context: str = ""
|
||||
# Optional phone number. When S2S_INJECT_PROFILE is true the proxy fetches
|
||||
# the caller profile from VOCERO_USER_PHONE_AUTH_URL and:
|
||||
# 1. prepends the serialized profile to user_context before feeding the
|
||||
# engine (NODE_RED or OPENAI);
|
||||
# 2. appends the profile context to the LLM instructions prompt.
|
||||
phoneNumber: str | None = None
|
||||
# Optional podcast episode ID. When set the proxy fetches the episode from
|
||||
# the Aquachile AzurianLab API and injects it as the PRIMARY context into
|
||||
# both user_context (prepended) and LLM instructions prompt (appended first).
|
||||
episode_id: str | None = None
|
||||
|
||||
|
||||
class ApipilotExecuteRequest(BaseModel):
|
||||
"""Body for the ApiPilot execute proxy endpoint. Mirrors §2.2 request shape."""
|
||||
|
||||
name: str
|
||||
arguments: dict = {}
|
||||
|
||||
|
||||
class QueueEndPayload(BaseModel):
|
||||
"""A view of a decoded beacon object, preserving the legacy loose value.
|
||||
|
||||
Missing/invalid JSON and non-object bodies are still handled by the route.
|
||||
In particular, a truthy non-string ID must retain its existing behavior.
|
||||
"""
|
||||
|
||||
model_config = ConfigDict(extra="allow")
|
||||
queueId: Any = ""
|
||||
@@ -0,0 +1,125 @@
|
||||
"""Response contracts without imposing new assumptions on upstream JSON.
|
||||
|
||||
Only fields constructed by this service have concrete types. Upstream-owned
|
||||
values remain Any, and unknown fields remain allowed at every modeled level.
|
||||
Responses are validated but serialized from their original payloads so omitted
|
||||
fields, numeric representations, key order, and unknown values stay unchanged.
|
||||
"""
|
||||
|
||||
from typing import Any, Literal
|
||||
|
||||
from pydantic import BaseModel, ConfigDict, RootModel
|
||||
|
||||
|
||||
class OpenResponse(BaseModel):
|
||||
model_config = ConfigDict(extra="allow", strict=True)
|
||||
|
||||
|
||||
class ConfigResponse(OpenResponse):
|
||||
search: bool
|
||||
lb: bool
|
||||
allowDirect: bool
|
||||
s2sUrl: str
|
||||
primaryPrompt: str
|
||||
reasoningType: Literal["PROXY", "OPENAI", "NODE_RED"]
|
||||
injectProfile: bool
|
||||
debugPrompt: bool
|
||||
startSessionMode: str
|
||||
theme: str
|
||||
apipilot: bool
|
||||
|
||||
|
||||
class SearchResult(OpenResponse):
|
||||
# Serper values have historically passed through, including nulls, numbers,
|
||||
# and objects. The service guarantees these keys, not their value types.
|
||||
title: Any
|
||||
snippet: Any
|
||||
url: Any
|
||||
|
||||
|
||||
class SearchResponse(OpenResponse):
|
||||
query: str
|
||||
answer: Any
|
||||
results: list[SearchResult]
|
||||
|
||||
|
||||
class ReportEntry(OpenResponse):
|
||||
sourceScheduleLabel: Any
|
||||
date: Any
|
||||
|
||||
|
||||
class ReportsResponse(OpenResponse):
|
||||
count: int
|
||||
wrappedLen: int
|
||||
hints: list[str]
|
||||
entries: list[ReportEntry]
|
||||
rawCount: int | None = None
|
||||
cap: int | None = None
|
||||
skipped: bool | None = None
|
||||
reason: str | None = None
|
||||
truncated: bool | None = None
|
||||
note: str | None = None
|
||||
|
||||
|
||||
class ToolInvocation(OpenResponse):
|
||||
name: str
|
||||
success: bool
|
||||
result_length: int
|
||||
|
||||
|
||||
class ReasoningResponse(OpenResponse):
|
||||
answer: str
|
||||
log_only: bool | None = None
|
||||
usage: Any = None
|
||||
usage_pass2: Any = None
|
||||
latency_ms: Any = None
|
||||
intent: Any = None
|
||||
caller_profile_keys: Any = None
|
||||
debug: Any = None
|
||||
apipilot_invoked: ToolInvocation | None = None
|
||||
|
||||
|
||||
class ToolDefinition(OpenResponse):
|
||||
name: str
|
||||
description: str
|
||||
parameters: dict[str, Any]
|
||||
requires_auth: bool
|
||||
|
||||
|
||||
class ToolCatalog(OpenResponse):
|
||||
count: int
|
||||
include_unauthorized: bool
|
||||
tools: list[ToolDefinition]
|
||||
|
||||
|
||||
class ToolCatalogResponse(OpenResponse):
|
||||
success: bool
|
||||
data: ToolCatalog | None
|
||||
error: Any
|
||||
|
||||
|
||||
class ToolExecutionResponse(OpenResponse):
|
||||
success: bool
|
||||
# The upstream may omit these fields or return any JSON value for them.
|
||||
data: Any = None
|
||||
error: Any = None
|
||||
|
||||
|
||||
class AllocationResponse(OpenResponse):
|
||||
"""LB-owned object: no new required fields or value-type restrictions."""
|
||||
|
||||
state: Any = None
|
||||
session_id: Any = None
|
||||
connect_url: Any = None
|
||||
pending_timeout_s: Any = None
|
||||
queue_id: Any = None
|
||||
position: Any = None
|
||||
poll_interval_s: Any = None
|
||||
|
||||
|
||||
class UserProfileResponse(RootModel[Any]):
|
||||
"""The profile endpoint relays objects, arrays, scalars, and null verbatim."""
|
||||
|
||||
|
||||
class QueueCancellationResponse(OpenResponse):
|
||||
ok: bool
|
||||
Reference in New Issue
Block a user