mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-08 03:08:45 +00:00
refactor(lint): allow dict and mapping annotations in LIT001
Main already retired LIT002 (#43971). This narrows LIT001 to mutable sequences and sets, so dict, Dict, DefaultDict, OrderedDict, Counter, ChainMap, defaultdict and MutableMapping annotations are allowed, nested list/set inside a mapping still trips, and the 945 mutable-ok suppressions that only covered mapping annotations are deleted (LIT013 now flags them). AGENTS.md guidance updated to match Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
parent
086bcd2a47
commit
22d584a4c1
272 changed files with 1157 additions and 1247 deletions
|
|
@ -62,7 +62,7 @@ Never edit or commit `ruff-strict-budget.json`, `type-discipline-budget.json`, `
|
|||
|
||||
If you're trying to create a new function that relies on untyped stuff, instead of adding more Any's and pushing `reportAny` / `reportExplicitAny` closer to their basedpyright ceilings, just validate it in the caller with Pydantic (a model or `TypeAdapter` that returns the typed thing or raises will do) and then pass the now typed variable in
|
||||
|
||||
If you get an LIT001 fail, refactor the code to follow functional programming best practices rather than introducing mutable data structures. For example, build values in one shot with comprehensions or generators wrapped in `tuple()` / `MappingProxyType()` / `frozenset()` instead of seeding an empty `list`/`dict`/`set` and mutating it over time. Ideally, `# mutable-ok` is never used; reach for it only as a genuine last resort when an immutable rewrite is truly impossible, and always pair it with a real reason
|
||||
If you get an LIT001 fail, refactor the code to follow functional programming best practices rather than introducing mutable sequences or sets. For example, build values in one shot with comprehensions or generators wrapped in `tuple()` / `frozenset()` instead of seeding an empty `list`/`set` and appending to it over time. Ideally, `# mutable-ok` is never used; reach for it only as a last resort when an immutable rewrite is impossible, and always pair it with a real reason. Plain `dict` is allowed: most of the Python ecosystem takes and returns dicts, and converting to `MappingProxyType` at every boundary costs more than it protects. Never deep copy a value just to hand out an immutable view; a defensive copy of a self-referential or large object is worse than the mutation it guards against
|
||||
|
||||
Every lint or type suppression must name the exact rule inside brackets and carry a reason comment, e.g. `# pyright: ignore[reportArgumentType] # stubs lack async overload` or `# noqa: TID251 # <reason>`. `# type: ignore` is banned (LIT009): pyrightconfig.json sets `enableTypeIgnoreComments` to false, so it silently does nothing
|
||||
|
||||
|
|
@ -93,7 +93,7 @@ Follow these coding conventions for new/updated code (a three-line fix in a lega
|
|||
- Composition over inheritance
|
||||
- Never-nester: early returns over deep nesting
|
||||
- Don't throw; model failures as values (One function (e.g., raise_public) maps error union to existing public exception contracts via exhaustive match + assert_never)
|
||||
- No mutation; don't reassign variables, global or local. Instead of mutable lists and dicts, prefer tuples, frozen dataclasses (with slots=True), `MappingProxyType`, etc.
|
||||
- No mutation; don't reassign variables, global or local. Prefer tuples over lists and frozensets over sets. For structured records prefer frozen dataclasses (with slots=True) or `ReadOnly` TypedDicts over dicts. A `dict` is fine for a mapping with arbitrary keys, especially at a library boundary; `MappingProxyType` is optional there, and never worth a copy
|
||||
- Annotate every variable with `: Final` (LIT010). Unpacking and walrus targets cannot carry the annotation, so they are implicitly final. Don't rebind them. Never rebind or mutate function parameters (LIT011); `self`/`cls` attribute stores are the exception. If rebinding or in-place mutation is truly unavoidable, suppress with `# rebind-ok: <reason>`
|
||||
- Qualify every TypedDict field with `ReadOnly[...]` (LIT012), which nests freely with `Required` / `NotRequired` / `Annotated` in any order. If making the key writable is truly unavoidable, suppress with `# writable-ok: <reason>`
|
||||
- Comprehensions take at most one `for` clause and one `if` clause (LIT014); split stacked clauses into a helper generator, a named intermediate, or a plain loop. Suppress with `# comprehension-ok: <reason>` only when unavoidable
|
||||
|
|
|
|||
|
|
@ -205,7 +205,7 @@ def _str_to_bool(value: str) -> bool:
|
|||
def _coerce_redis_kwargs_types(
|
||||
redis_kwargs: Mapping[str, object],
|
||||
client: type | tuple[type, ...] = redis.Redis,
|
||||
) -> dict[str, object]: # mutable-ok: a caller mutates the returned kwargs before constructing its client
|
||||
) -> dict[str, object]:
|
||||
"""Coerces string values to the numeric/boolean type ``client``'s constructor
|
||||
declares for that parameter. ``client`` may be a tuple of client classes; a
|
||||
parameter's type is taken from the first signature that declares it, which
|
||||
|
|
|
|||
|
|
@ -466,13 +466,13 @@ class RequestRedisBatches:
|
|||
)
|
||||
|
||||
def __init__(self, post_call_deadline: float = POST_CALL_FLUSH_DEADLINE_SECONDS) -> None:
|
||||
self._batches: Final[dict[object, RedisBatch]] = {} # mutable-ok: lazily filled per backend
|
||||
self._post_call: Final[dict[object, RedisBatch]] = {} # mutable-ok: lazily filled per backend
|
||||
self._batches: Final[dict[object, RedisBatch]] = {}
|
||||
self._post_call: Final[dict[object, RedisBatch]] = {}
|
||||
self.post_call_deadline: Final = post_call_deadline
|
||||
self._deadline: asyncio.TimerHandle | None = None
|
||||
self._deadline_flush: asyncio.Task[None] | None = None
|
||||
# Reads declared early for a consumer that runs later in the request, keyed by consumer name.
|
||||
self.prefetched: Final[dict[str, object]] = {} # mutable-ok: armed pre-admission, taken at use
|
||||
self.prefetched: Final[dict[str, object]] = {}
|
||||
|
||||
def batch(self, redis_cache: RedisCache) -> RedisBatch:
|
||||
key: Final = _backend_key(redis_cache)
|
||||
|
|
|
|||
|
|
@ -142,9 +142,7 @@ def get_litellm_async_redis_cluster_class( # noqa: C901 # supports redis-py ve
|
|||
self._litellm_reinit_requests = 0
|
||||
self._litellm_tolerated_timeouts = 0
|
||||
super().__init__(*args, **kwargs)
|
||||
self._litellm_consecutive_timeouts: dict[ # mutable-ok: per-node counter updated on the command hot path
|
||||
str, int
|
||||
] = {}
|
||||
self._litellm_consecutive_timeouts: dict[str, int] = {}
|
||||
|
||||
@property
|
||||
def _initialize(self) -> bool:
|
||||
|
|
|
|||
|
|
@ -1382,7 +1382,7 @@ class OpenAiResponsesToChatCompletionStreamIterator(BaseModelResponseIterator):
|
|||
super().__init__(streaming_response, sync_stream, json_mode)
|
||||
self._chat_completion_id: str | None = None
|
||||
self._served_service_tier: str | None = None
|
||||
self._tool_call_index_map: dict[int, int] = {} # mutable-ok: per-stream accumulator state
|
||||
self._tool_call_index_map: dict[int, int] = {}
|
||||
|
||||
def _handle_string_chunk(
|
||||
self, str_line: Union[str, "BaseModel"]
|
||||
|
|
@ -1403,7 +1403,7 @@ class OpenAiResponsesToChatCompletionStreamIterator(BaseModelResponseIterator):
|
|||
|
||||
@staticmethod
|
||||
def _sequential_tool_call_index(
|
||||
tool_call_index_map: dict[int, int] | None, # mutable-ok: per-stream state, remapped in place
|
||||
tool_call_index_map: dict[int, int] | None,
|
||||
output_index: int,
|
||||
) -> int:
|
||||
"""Chat-completions tool_call indices must be 0-based and sequential, but
|
||||
|
|
@ -1422,7 +1422,7 @@ class OpenAiResponsesToChatCompletionStreamIterator(BaseModelResponseIterator):
|
|||
@staticmethod
|
||||
def translate_responses_chunk_to_openai_stream(
|
||||
parsed_chunk: dict | BaseModel,
|
||||
tool_call_index_map: dict[int, int] | None = None, # mutable-ok: per-stream state, remapped in place
|
||||
tool_call_index_map: dict[int, int] | None = None,
|
||||
) -> "ModelResponseStream":
|
||||
"""
|
||||
Translate a Responses API streaming chunk to OpenAI chat completion streaming format.
|
||||
|
|
|
|||
|
|
@ -15,9 +15,7 @@ from litellm.harness.types import Approval, Harness, PermissionMode
|
|||
if TYPE_CHECKING:
|
||||
from litellm.harness.endpoint import ModelEndpoint
|
||||
|
||||
ApprovalHandler: TypeAlias = Callable[
|
||||
[Approval], bool | Awaitable[bool] # mutable-ok: Callable parameter list in a type alias, not a runtime collection
|
||||
]
|
||||
ApprovalHandler: TypeAlias = Callable[[Approval], bool | Awaitable[bool]]
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
|
|
|
|||
|
|
@ -303,7 +303,7 @@ def gateway_headers(
|
|||
for name, value in incoming.items()
|
||||
if name.lower() not in DROPPED_REQUEST_HEADERS and not name.lower().startswith("x-litellm-")
|
||||
)
|
||||
metadata_json = json.dumps(dict(metadata), default=str) if metadata else None # mutable-ok: for json.dumps
|
||||
metadata_json = json.dumps(dict(metadata), default=str) if metadata else None
|
||||
metadata_header = (("x-litellm-spend-logs-metadata", metadata_json),) if metadata_json is not None else ()
|
||||
added = (
|
||||
("authorization", f"Bearer {gateway.api_key}"),
|
||||
|
|
@ -333,15 +333,15 @@ def error_status(exc: BaseException) -> int:
|
|||
return 500
|
||||
|
||||
|
||||
def error_body(exc: BaseException, message: str) -> dict[str, dict[str, str]]: # mutable-ok: JSONResponse body
|
||||
return {"error": {"type": type(exc).__name__, "message": message}} # mutable-ok: JSONResponse body
|
||||
def error_body(exc: BaseException, message: str) -> dict[str, dict[str, str]]:
|
||||
return {"error": {"type": type(exc).__name__, "message": message}}
|
||||
|
||||
|
||||
def to_jsonable(obj: object) -> object:
|
||||
if hasattr(obj, "model_dump"):
|
||||
return obj.model_dump(mode="json", exclude_none=True)
|
||||
if isinstance(obj, Mapping):
|
||||
return dict(obj) # mutable-ok: plain-dict copy so json.dumps can serialize any Mapping
|
||||
return dict(obj)
|
||||
return obj
|
||||
|
||||
|
||||
|
|
@ -457,9 +457,7 @@ class ModelEndpoint:
|
|||
return self._injected_client
|
||||
handler = get_async_httpx_client(
|
||||
llm_provider=httpxSpecialProvider.AgentHarness,
|
||||
params={ # mutable-ok: get_async_httpx_client takes a dict params argument
|
||||
"timeout": HARNESS_ENDPOINT_REQUEST_TIMEOUT_SECONDS
|
||||
},
|
||||
params={"timeout": HARNESS_ENDPOINT_REQUEST_TIMEOUT_SECONDS},
|
||||
)
|
||||
return handler.client
|
||||
|
||||
|
|
@ -494,17 +492,12 @@ class ModelEndpoint:
|
|||
Route(
|
||||
f"{prefix}/{route}",
|
||||
self._handle,
|
||||
methods=["POST"], # mutable-ok: Starlette Route takes a methods list
|
||||
methods=["POST"],
|
||||
)
|
||||
for prefix, route in itertools.product(ROUTE_PREFIXES, POST_ROUTES)
|
||||
)
|
||||
get_routes = tuple(
|
||||
Route(f"{prefix}/models", self._models, methods=["GET"]) # mutable-ok: Starlette Route takes a methods list
|
||||
for prefix in ROUTE_PREFIXES
|
||||
)
|
||||
return deps.applications.Starlette(
|
||||
routes=[*post_routes, *get_routes] # mutable-ok: Starlette takes a routes list
|
||||
)
|
||||
get_routes = tuple(Route(f"{prefix}/models", self._models, methods=["GET"]) for prefix in ROUTE_PREFIXES)
|
||||
return deps.applications.Starlette(routes=[*post_routes, *get_routes])
|
||||
|
||||
@property
|
||||
def _responses(self) -> _ResponsesModule:
|
||||
|
|
@ -521,7 +514,7 @@ class ModelEndpoint:
|
|||
|
||||
def _unauthorized(self) -> Response:
|
||||
return self._json(
|
||||
{"error": {"type": "authentication_error", "message": "invalid token"}}, # mutable-ok: JSONResponse body
|
||||
{"error": {"type": "authentication_error", "message": "invalid token"}},
|
||||
401,
|
||||
)
|
||||
|
||||
|
|
@ -536,9 +529,9 @@ class ModelEndpoint:
|
|||
async def _models(self, request: Request) -> Response:
|
||||
if not self._authorized(request):
|
||||
return self._unauthorized()
|
||||
entry = {"id": self.model, "object": "model", "created": 0, "owned_by": "litellm"} # mutable-ok: JSON body
|
||||
entry = {"id": self.model, "object": "model", "created": 0, "owned_by": "litellm"}
|
||||
data = (entry,) if self.model else ()
|
||||
return self._json({"object": "list", "data": data}) # mutable-ok: JSON response body for Starlette JSONResponse
|
||||
return self._json({"object": "list", "data": data})
|
||||
|
||||
async def _handle(self, request: Request) -> Response:
|
||||
if not self._authorized(request):
|
||||
|
|
@ -574,7 +567,7 @@ class ModelEndpoint:
|
|||
if self._client is None or self.gateway is None:
|
||||
raise HarnessError("gateway client is not started")
|
||||
if self.model:
|
||||
body = {**body, "model": self.model} # mutable-ok: JSON request body re-sent upstream via httpx json=
|
||||
body = {**body, "model": self.model}
|
||||
upstream_request = self._client.build_request(
|
||||
"POST",
|
||||
f"{self.gateway.api_base}/v1/{route}",
|
||||
|
|
@ -626,10 +619,8 @@ class ModelEndpoint:
|
|||
tokens = (0, 0)
|
||||
self._record(model, tokens[0], tokens[1], header_cost(upstream.headers))
|
||||
|
||||
def _sdk_kwargs(
|
||||
self, body: Mapping[str, object]
|
||||
) -> dict[str, object]: # mutable-ok: SDK call kwargs, mutated by _invoke_sdk then splatted
|
||||
kwargs: dict[str, object] = {**body} # mutable-ok: SDK call kwargs built from the JSON body, then overridden
|
||||
def _sdk_kwargs(self, body: Mapping[str, object]) -> dict[str, object]:
|
||||
kwargs: dict[str, object] = {**body}
|
||||
if self.model:
|
||||
kwargs["model"] = self.model
|
||||
if self.api_key:
|
||||
|
|
@ -641,14 +632,14 @@ class ModelEndpoint:
|
|||
async def _invoke_sdk(
|
||||
self,
|
||||
route: str,
|
||||
kwargs: dict[str, Any], # mutable-ok: injects stream_options into the SDK kwargs
|
||||
kwargs: dict[str, Any],
|
||||
) -> object:
|
||||
if route == ROUTE_MESSAGES:
|
||||
return await litellm.anthropic.messages.acreate(**kwargs)
|
||||
if route == ROUTE_CHAT:
|
||||
if kwargs.get("stream"):
|
||||
stream_options = kwargs.get("stream_options") or {} # mutable-ok: empty default for a JSON field
|
||||
kwargs["stream_options"] = { # mutable-ok: JSON field sent to litellm.acompletion
|
||||
stream_options = kwargs.get("stream_options") or {}
|
||||
kwargs["stream_options"] = {
|
||||
"include_usage": True,
|
||||
**stream_options,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ def sandbox_path(private_dir: str, path: str) -> str:
|
|||
|
||||
async def persist_dir(sandbox: Sandbox, link_path: str, cache_subpath: str) -> None:
|
||||
script_args: Final = ("-c", PERSIST_DIR_SCRIPT, "sh", link_path, cache_subpath)
|
||||
cmd: Final = ["sh", *script_args] # mutable-ok: Sandbox.run takes list[str]
|
||||
cmd: Final = ["sh", *script_args]
|
||||
run = await sandbox.run(cmd)
|
||||
if run.exit_code != 0:
|
||||
verbose_logger.debug(
|
||||
|
|
@ -120,7 +120,7 @@ class CLIHarnessHandler(BaseHarnessHandler):
|
|||
if self._setup is None or self._private_dir is None:
|
||||
raise RuntimeError("CLIHarnessHandler.turn() called before start()")
|
||||
request = self.config.transform_turn_request(ctx, self._setup, self._private_dir, prompt, self._native_id)
|
||||
argv: Final = list(request.argv) # mutable-ok: Sandbox.exec takes list[str]
|
||||
argv: Final = list(request.argv)
|
||||
proc = await ctx.sandbox.exec(argv, env=request.env, cwd=request.cwd)
|
||||
self._proc = proc
|
||||
tail: Final[deque[str]] = deque(maxlen=HARNESS_STDERR_TAIL_LINES) # mutable-ok: bounded stderr ring buffer
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ def load_deps() -> DeepAgentsDeps:
|
|||
)
|
||||
|
||||
|
||||
_SHARED_CHECKPOINTER: dict[str, Any] = {} # mutable-ok: process-wide lazy singleton slot for the in-memory checkpointer
|
||||
_SHARED_CHECKPOINTER: dict[str, Any] = {}
|
||||
|
||||
|
||||
def shared_checkpointer(deps: DeepAgentsDeps) -> BaseCheckpointSaver:
|
||||
|
|
@ -129,7 +129,7 @@ class DeepAgentsHandler(BaseHarnessHandler):
|
|||
)
|
||||
self._agent = deps.create_deep_agent(
|
||||
model=build_chat_model(ctx, deps),
|
||||
tools=list(ctx.tools), # mutable-ok: deepagents create_deep_agent(tools=) takes a list
|
||||
tools=list(ctx.tools),
|
||||
system_prompt=ctx.instructions,
|
||||
middleware=self._middleware(deps, blocked),
|
||||
subagents=self._subagents(ctx, deps, blocked),
|
||||
|
|
@ -166,39 +166,39 @@ class DeepAgentsHandler(BaseHarnessHandler):
|
|||
async def turn(self, ctx: SessionContext, prompt: str) -> AsyncIterator[Event]:
|
||||
agent, deps = self._require_agent()
|
||||
run_config = self._run_config(ctx, deps.backend.UsageCallback(ctx, ctx.model))
|
||||
user_message = {"role": "user", "content": prompt} # mutable-ok: LangGraph input message dict
|
||||
payload: dict[str, object] | Command = {"messages": [user_message]} # mutable-ok: LangGraph input state
|
||||
user_message = {"role": "user", "content": prompt}
|
||||
payload: dict[str, object] | Command = {"messages": [user_message]}
|
||||
while True:
|
||||
state = TurnState()
|
||||
async for event in self._stream_pass(agent, payload, run_config, state):
|
||||
yield event
|
||||
if not state.interrupts:
|
||||
break
|
||||
resume: dict[str, object] = {} # mutable-ok: Command(resume=) payload, filled per answered approval
|
||||
resume: dict[str, object] = {}
|
||||
for interrupt in state.interrupts:
|
||||
decisions: list[dict[str, Any]] = [] # mutable-ok: HITL decisions collected across awaited approvals
|
||||
for request in approval_requests(getattr(interrupt, "value", None)):
|
||||
approval = Approval(
|
||||
tool=normalized_tool_name(str(request.get("name") or "")),
|
||||
input=dict(request.get("args") or ()), # mutable-ok: Approval.input is a public dict field
|
||||
input=dict(request.get("args") or ()),
|
||||
)
|
||||
yield approval
|
||||
decisions.append(decision(*await approval.wait()))
|
||||
resume[interrupt.id] = {"decisions": decisions} # mutable-ok: LangGraph HITL resume payload
|
||||
resume[interrupt.id] = {"decisions": decisions}
|
||||
payload = deps.command_cls(resume=resume)
|
||||
await self._finish_turn(ctx, agent, run_config)
|
||||
|
||||
async def _stream_pass(
|
||||
self,
|
||||
agent: CompiledStateGraph,
|
||||
payload: dict[str, object] | Command, # mutable-ok: LangGraph astream input type
|
||||
payload: dict[str, object] | Command,
|
||||
run_config: RunnableConfig,
|
||||
state: TurnState,
|
||||
) -> AsyncIterator[Event]:
|
||||
async for part in agent.astream(
|
||||
payload,
|
||||
run_config,
|
||||
stream_mode=["messages", "updates"], # mutable-ok: LangGraph stream_mode takes a list
|
||||
stream_mode=["messages", "updates"],
|
||||
):
|
||||
# A list stream_mode yields (mode, chunk) tuples; LangGraph's overloads don't say so.
|
||||
if not isinstance(part, tuple) or len(part) != 2:
|
||||
|
|
@ -232,13 +232,13 @@ class DeepAgentsHandler(BaseHarnessHandler):
|
|||
"recursion_limit": recursion_limit(ctx),
|
||||
}
|
||||
if usage_callback is not None:
|
||||
run_config["callbacks"] = [usage_callback] # mutable-ok: LangChain RunnableConfig.callbacks is a list
|
||||
run_config["callbacks"] = [usage_callback]
|
||||
return run_config
|
||||
|
||||
@staticmethod
|
||||
def _middleware(deps: DeepAgentsDeps, blocked: frozenset[str]) -> list[object]: # mutable-ok: deepagents API
|
||||
filters = (deps.backend.ToolFilterMiddleware(blocked),) if blocked else ()
|
||||
return list(filters) # mutable-ok: deepagents create_deep_agent(middleware=) takes a list
|
||||
return list(filters)
|
||||
|
||||
def _subagents(
|
||||
self, ctx: SessionContext, deps: DeepAgentsDeps, blocked: frozenset[str]
|
||||
|
|
@ -249,13 +249,13 @@ class DeepAgentsHandler(BaseHarnessHandler):
|
|||
has_general = any(
|
||||
isinstance(s, Mapping) and s.get("name") == deps.subagent_defaults["name"] for s in user_subagents
|
||||
)
|
||||
spec = {**deps.subagent_defaults, "middleware": self._middleware(deps, blocked)} # mutable-ok: SubAgent dict
|
||||
spec = {**deps.subagent_defaults, "middleware": self._middleware(deps, blocked)}
|
||||
general = (spec,) if blocked and not has_general else ()
|
||||
return [*general, *user_subagents] # mutable-ok: deepagents create_deep_agent(subagents=) takes a list
|
||||
return [*general, *user_subagents]
|
||||
|
||||
@staticmethod
|
||||
async def _install_skills(ctx: SessionContext) -> list[str] | None: # mutable-ok: deepagents skills= takes a list
|
||||
if not ctx.skills:
|
||||
return None
|
||||
await copy_skills(ctx.sandbox, ctx.skills, f"{ctx.sandbox.workdir}/{SKILLS_DIR}")
|
||||
return [f"/{SKILLS_DIR}/"] # mutable-ok: deepagents create_deep_agent(skills=) takes a list
|
||||
return [f"/{SKILLS_DIR}/"]
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ def _normalize_tool_call(
|
|||
return _FunctionToolCall(id=call.id, name=call.custom.name, arguments=call.custom.input)
|
||||
|
||||
|
||||
def _parse_arguments(raw: str) -> tuple[dict[str, object], str | None]: # mutable-ok: event input uses a dict
|
||||
def _parse_arguments(raw: str) -> tuple[dict[str, object], str | None]:
|
||||
text: Final = raw.strip()
|
||||
try:
|
||||
raw_decoded: object = _JSON_DECODER.raw_decode(text)
|
||||
|
|
@ -195,7 +195,7 @@ async def _execute_tool(tool: FunctionTool, arguments: Mapping[str, object]) ->
|
|||
positional_args: Final = tuple(
|
||||
validated[parameter.name] for parameter in parameters if parameter.kind is inspect.Parameter.POSITIONAL_ONLY
|
||||
)
|
||||
keyword_args: Final[dict[str, object]] = { # mutable-ok: tool calls need keyword arguments
|
||||
keyword_args: Final[dict[str, object]] = {
|
||||
parameter.name: validated[parameter.name]
|
||||
for parameter in parameters
|
||||
if parameter.kind is not inspect.Parameter.POSITIONAL_ONLY
|
||||
|
|
@ -268,7 +268,7 @@ class ToolLoopHandler(BaseHarnessHandler):
|
|||
tool_specs: list[ChatCompletionToolParam] = copy.deepcopy( # mutable-ok: acompletion takes tool list
|
||||
list(self._tool_specs)
|
||||
)
|
||||
kwargs: dict[str, object] = { # mutable-ok: acompletion takes keyword arguments
|
||||
kwargs: dict[str, object] = {
|
||||
**{key: value for key, value in self._completion_kwargs.items() if key not in {"messages", "tools"}},
|
||||
"messages": messages,
|
||||
**({"tools": tool_specs} if tool_specs else {}),
|
||||
|
|
|
|||
|
|
@ -461,9 +461,7 @@ class _Turn:
|
|||
sandbox = self.ctx.sandbox
|
||||
after = await sandbox.snapshot()
|
||||
files = await build_file_changes(sandbox, self.before, after, self.before_contents)
|
||||
seen = { # mutable-ok: dedupe set grown while merging streamed FileChange events
|
||||
change.path for change in files
|
||||
}
|
||||
seen = {change.path for change in files}
|
||||
for event in self.events:
|
||||
if isinstance(event, FileChange) and event.path not in seen:
|
||||
files.append(event)
|
||||
|
|
@ -496,9 +494,7 @@ class _Turn:
|
|||
text=self._text(),
|
||||
output=output,
|
||||
files=files,
|
||||
events=list( # mutable-ok: Result.events is a public list field; copy detaches it from the accumulator
|
||||
self.events
|
||||
),
|
||||
events=list(self.events),
|
||||
usage=usage,
|
||||
cost=cost,
|
||||
stop_reason=self.stop_reason,
|
||||
|
|
|
|||
|
|
@ -124,7 +124,7 @@ class DockerSandbox:
|
|||
env_args = tuple(
|
||||
arg for key, value in self.env.items() for arg in ("-e", f"{key}={value}")
|
||||
) # comprehension-ok: flattens (flag, value) pairs into argv
|
||||
return [ # mutable-ok: argv is returned as a list, the shape callers and tests compare against
|
||||
return [
|
||||
"run",
|
||||
"-d",
|
||||
"--rm",
|
||||
|
|
@ -150,7 +150,7 @@ class DockerSandbox:
|
|||
env_args = tuple(
|
||||
arg for key, value in (env.items() if env else ()) for arg in ("-e", f"{key}={value}")
|
||||
) # comprehension-ok: flattens (flag, value) pairs into argv
|
||||
return [ # mutable-ok: argv is returned as a list, the shape callers and tests compare against
|
||||
return [
|
||||
"exec",
|
||||
"-i",
|
||||
"-w",
|
||||
|
|
@ -257,9 +257,7 @@ class DockerSandbox:
|
|||
self._processes.clear()
|
||||
if self.container_id is not None:
|
||||
container_id, self.container_id = self.container_id, None
|
||||
await self._docker(
|
||||
["rm", "-f", container_id] # mutable-ok: argv list, the shape _spawn records and tests assert on
|
||||
)
|
||||
await self._docker(["rm", "-f", container_id])
|
||||
|
||||
async def __aenter__(self) -> DockerSandbox:
|
||||
await self.start()
|
||||
|
|
|
|||
|
|
@ -60,9 +60,7 @@ def _hash_entry(root: str, dirpath: str, filename: str) -> tuple[str, str] | Non
|
|||
|
||||
def _walk_entries(root: str) -> Iterator[tuple[str, str]]:
|
||||
for dirpath, dirnames, filenames in os.walk(root, followlinks=False):
|
||||
dirnames[:] = [ # mutable-ok: os.walk prunes only via in-place mutation of its dirnames list
|
||||
d for d in dirnames if d not in HARNESS_SNAPSHOT_SKIP_DIRS
|
||||
]
|
||||
dirnames[:] = [d for d in dirnames if d not in HARNESS_SNAPSHOT_SKIP_DIRS]
|
||||
for filename in filenames:
|
||||
entry = _hash_entry(root, dirpath, filename)
|
||||
if entry is not None:
|
||||
|
|
@ -94,9 +92,7 @@ def diff_snapshots(
|
|||
) -> list[tuple[str, FileChangeKind]]: # mutable-ok: public sandbox helper; callers compare against a list
|
||||
"""Return (path, kind) for every changed file, sorted by path."""
|
||||
kinds = ((path, _change_kind(path, before, after)) for path in sorted(frozenset(before) | frozenset(after)))
|
||||
return [ # mutable-ok: public sandbox helper returns a list
|
||||
(path, kind) for path, kind in kinds if kind is not None
|
||||
]
|
||||
return [(path, kind) for path, kind in kinds if kind is not None]
|
||||
|
||||
|
||||
def _as_text(data: bytes) -> str | None:
|
||||
|
|
@ -134,7 +130,7 @@ async def capture_text_contents(sandbox: Sandbox, paths_hashes: Mapping[str, str
|
|||
Each kept file is <= HARNESS_MAX_DIFF_BYTES; every byte read (kept or not) counts
|
||||
toward HARNESS_SNAPSHOT_MAX_TOTAL_BYTES, after which capture stops.
|
||||
"""
|
||||
captured: dict[str, bytes] = {} # mutable-ok: async accumulator (awaits per read), frozen on return
|
||||
captured: dict[str, bytes] = {}
|
||||
total = 0
|
||||
for path in sorted(paths_hashes):
|
||||
if total >= HARNESS_SNAPSHOT_MAX_TOTAL_BYTES:
|
||||
|
|
@ -178,6 +174,4 @@ async def build_file_changes(
|
|||
) -> list[FileChange]: # mutable-ok: feeds the public Result.files list
|
||||
"""FileChange per changed path. diff is None when it cannot be built as text."""
|
||||
contents: Mapping[str, bytes] = before_contents or MappingProxyType({})
|
||||
return [ # mutable-ok: feeds the public Result.files list
|
||||
await _change_for(sandbox, path, kind, contents) for path, kind in diff_snapshots(before, after)
|
||||
]
|
||||
return [await _change_for(sandbox, path, kind, contents) for path, kind in diff_snapshots(before, after)]
|
||||
|
|
|
|||
|
|
@ -199,7 +199,7 @@ class Session:
|
|||
|
||||
@property
|
||||
def results(self) -> list[Result]: # mutable-ok: public property; returns a detached copy of the session's results
|
||||
return list(self._inner.results) # mutable-ok: detached copy so callers cannot mutate the session's accumulator
|
||||
return list(self._inner.results)
|
||||
|
||||
@property
|
||||
def session_id(self) -> str:
|
||||
|
|
|
|||
|
|
@ -187,7 +187,7 @@ class State:
|
|||
|
||||
def dumps(self) -> bytes:
|
||||
return json.dumps(
|
||||
{ # mutable-ok: JSON payload serialized immediately by json.dumps
|
||||
{
|
||||
"harness": self.harness.value,
|
||||
"native_session_id": self.native_session_id,
|
||||
"workdir": self.workdir,
|
||||
|
|
|
|||
|
|
@ -345,7 +345,7 @@ class CustomGuardrail(CustomLogger):
|
|||
|
||||
def inject_advisory_message(
|
||||
self,
|
||||
data: dict[str, Any], # mutable-ok: caller's dict is mutated in place, matching mark_pre_call_hook_ran
|
||||
data: dict[str, Any],
|
||||
message: str,
|
||||
) -> bool:
|
||||
"""
|
||||
|
|
@ -872,7 +872,7 @@ class CustomGuardrail(CustomLogger):
|
|||
)
|
||||
|
||||
target: Final = self._deployment_hook_target()
|
||||
scan_request: Final[dict[str, object]] = { # mutable-ok: async_pre_call_hook writes into the dict it is handed
|
||||
scan_request: Final[dict[str, object]] = {
|
||||
**{key: value for key, value in request_data.items() if key not in _PRE_CALL_CONTENT_KEYS},
|
||||
"messages": list(messages),
|
||||
**({} if target is self else _unified_hook_fields(self, request_data)),
|
||||
|
|
@ -944,10 +944,10 @@ class CustomGuardrail(CustomLogger):
|
|||
|
||||
async def async_logging_hook(
|
||||
self,
|
||||
kwargs: dict, # mutable-ok: CustomLogger.async_logging_hook contract
|
||||
kwargs: dict,
|
||||
result: object,
|
||||
call_type: str,
|
||||
) -> tuple[dict, object]: # mutable-ok: CustomLogger.async_logging_hook contract
|
||||
) -> tuple[dict, object]:
|
||||
"""logging_only: run apply_guardrail on copies of the logged request/response and record the verdict."""
|
||||
from litellm.llms import get_guardrail_translation_mapping
|
||||
|
||||
|
|
@ -997,11 +997,11 @@ class CustomGuardrail(CustomLogger):
|
|||
|
||||
async def _scan_logged_call(
|
||||
self,
|
||||
kwargs: dict, # mutable-ok: CustomLogger.async_logging_hook contract
|
||||
kwargs: dict,
|
||||
response: object | None,
|
||||
translation: "BaseTranslation",
|
||||
output_translation: "BaseTranslation",
|
||||
scratch_metadata: dict, # mutable-ok: apply_guardrail records its verdict into request metadata
|
||||
scratch_metadata: dict,
|
||||
) -> None:
|
||||
optional_params: Final = kwargs.get("optional_params") or {}
|
||||
scratch_input: Final = copy.deepcopy(kwargs.get("messages") or kwargs.get("input"))
|
||||
|
|
@ -1567,7 +1567,7 @@ def _original_inputs_for(
|
|||
kwargs: Mapping[str, object],
|
||||
request_data: Mapping[str, object],
|
||||
event_type: GuardrailEventHooks | None,
|
||||
) -> dict | None: # mutable-ok: matches _process_response(original_inputs=) signature
|
||||
) -> dict | None:
|
||||
"""Baseline the hook's return value is compared against to decide "allow" vs "mask".
|
||||
|
||||
Hooks may edit their argument in place and return it, so the baseline is always a deep
|
||||
|
|
|
|||
|
|
@ -884,7 +884,7 @@ class _Lease:
|
|||
|
||||
|
||||
_TRACING_LOCK: Final = threading.Lock()
|
||||
_TRACING: Final[dict[_TracingKey, _Lease]] = {} # mutable-ok: process-wide channel cache, guarded by _TRACING_LOCK
|
||||
_TRACING: Final[dict[_TracingKey, _Lease]] = {}
|
||||
|
||||
|
||||
def acquire_langfuse_tracing(
|
||||
|
|
@ -1108,9 +1108,9 @@ class LangfuseApiClient:
|
|||
def __init__(self, api: LangfuseAPI, *, prompt_cache_ttl_seconds: float) -> None:
|
||||
self.api: Final = api
|
||||
self.prompt_cache_ttl_seconds: Final = prompt_cache_ttl_seconds
|
||||
# mutable-ok: per-client prompt cache, guarded by _lock
|
||||
|
||||
self._prompts: Final[dict[_PromptKey, _CachedPrompt]] = {}
|
||||
# mutable-ok: keys with a refresh in flight, guarded by _lock
|
||||
|
||||
self._refreshing: Final[set[_PromptKey]] = set()
|
||||
self._lock: Final = threading.Lock()
|
||||
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ class OTLPJsonSpanExporter(OTLPSpanExporter):
|
|||
def __init__(
|
||||
self,
|
||||
endpoint: str | None,
|
||||
headers: dict[str, str], # mutable-ok: SDK __init__ takes Dict
|
||||
headers: dict[str, str],
|
||||
certificate_file: str | None = None,
|
||||
session: "requests.Session | None" = None,
|
||||
) -> None:
|
||||
|
|
|
|||
|
|
@ -624,12 +624,12 @@ class TenantFanOutSpanProcessor(SpanProcessor):
|
|||
self._closed = False # guarded by ``_lock``: an unlocked read races the teardown it gates
|
||||
self._draining = False # guarded by ``_lock``: shutdown is flushing, nothing is held any more
|
||||
self._build: Final = processor_factory if processor_factory is not None else _destination_processor
|
||||
self._processors: OrderedDict[object, SpanProcessor] = OrderedDict() # mutable-ok: bounded LRU
|
||||
self._retired: OrderedDict[int, SpanProcessor] = OrderedDict() # mutable-ok: drains as exports finish
|
||||
self._exporting: dict[int, int] = {} # mutable-ok: per-processor in-flight export count
|
||||
self._pending: OrderedDict[int, _PendingTree] = OrderedDict() # mutable-ok: bounded, by trace id
|
||||
self._open: OrderedDict[int, int] = OrderedDict() # mutable-ok: bounded, spans in flight by trace id
|
||||
self._verdicts: OrderedDict[_VerdictKey, bool] = OrderedDict() # mutable-ok: bounded LRU
|
||||
self._processors: OrderedDict[object, SpanProcessor] = OrderedDict()
|
||||
self._retired: OrderedDict[int, SpanProcessor] = OrderedDict()
|
||||
self._exporting: dict[int, int] = {}
|
||||
self._pending: OrderedDict[int, _PendingTree] = OrderedDict()
|
||||
self._open: OrderedDict[int, int] = OrderedDict()
|
||||
self._verdicts: OrderedDict[_VerdictKey, bool] = OrderedDict()
|
||||
self._drain: Final = drain_pool if drain_pool is not None else _DrainPool(capacity=pending_drains)
|
||||
|
||||
def on_start(self, span: SDKSpan, parent_context: Context | None = None) -> None:
|
||||
|
|
@ -730,7 +730,7 @@ class TenantFanOutSpanProcessor(SpanProcessor):
|
|||
tree: Final = self._pending.pop(trace_id, None)
|
||||
if tree is None:
|
||||
return ()
|
||||
verdicts: dict[_VerdictKey, bool] = {} # mutable-ok: one draw per destination of this tree
|
||||
verdicts: dict[_VerdictKey, bool] = {}
|
||||
for _, destination in tree.held:
|
||||
key = _verdict_key(trace_id, destination)
|
||||
if key not in verdicts:
|
||||
|
|
|
|||
|
|
@ -172,9 +172,9 @@ class TenantTracerCache:
|
|||
# updates, span counts, and retirement must be atomic.
|
||||
self._lock: Final = threading.Lock()
|
||||
self._providers: OrderedDict[_RouteKey, TracerProvider] = OrderedDict()
|
||||
self._open_span_counts: dict[TracerProvider, int] = {} # mutable-ok: live refcount state
|
||||
self._open_span_counts: dict[TracerProvider, int] = {}
|
||||
# Oldest-first so an overflow of draining providers sheds the stalest.
|
||||
self._retired: OrderedDict[TracerProvider, None] = OrderedDict() # mutable-ok: draining evicted providers
|
||||
self._retired: OrderedDict[TracerProvider, None] = OrderedDict()
|
||||
# An owned exporter is routable only when its kind actually resolves to a
|
||||
# header-carrying OTLP exporter. A denylist would accept a typo'd or
|
||||
# unavailable kind, which ``_exporter_from_spec`` falls back to a
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ def signoz_dynamic_endpoint(params: StandardCallbackDynamicParams) -> str | None
|
|||
|
||||
def signoz_dynamic_headers(
|
||||
params: StandardCallbackDynamicParams,
|
||||
) -> dict[str, str]: # mutable-ok: DYNAMIC_HEADERS_BY_CALLBACK returns a dict
|
||||
) -> dict[str, str]:
|
||||
key: Final = params.get("signoz_ingestion_key")
|
||||
if _tenant_endpoint_is_unusable(params) or not key:
|
||||
return {}
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ class SharedPrometheusSeriesAdmissions:
|
|||
|
||||
def __init__(self, directory: str) -> None:
|
||||
self._directory = directory
|
||||
self._admissions: dict[str, _MetricAdmissions] = {} # mutable-ok: one entry per metric, added on first use
|
||||
self._admissions: dict[str, _MetricAdmissions] = {}
|
||||
self.lock = RLock()
|
||||
|
||||
def admit_series(self, metric_name: str, label_values: tuple[str, ...], max_series: int) -> bool:
|
||||
|
|
|
|||
|
|
@ -412,7 +412,7 @@ class S3Logger(CustomBatchLogger, BaseAWSLLM):
|
|||
|
||||
def _sign_put(
|
||||
self, credentials: "Credentials", url: str, json_string: str, headers: Mapping[str, str]
|
||||
) -> dict[str, str]: # mutable-ok: [LIT001] AsyncHTTPHandler.put/HTTPHandler.put only accept dict headers
|
||||
) -> dict[str, str]:
|
||||
"""
|
||||
``RefreshableCredentials`` (IMDS roles) may refresh between the access key, secret and token
|
||||
reads SigV4 performs, producing a mixed-generation signature that S3 rejects with 403.
|
||||
|
|
|
|||
|
|
@ -847,7 +847,7 @@ class ShadowEvalLogger(CustomLogger):
|
|||
self._inflight_shadow_tasks: int = 0
|
||||
# Starts per job since the last cache fill, never decremented within a
|
||||
# generation; the refill absorbs written rows and resets.
|
||||
self._job_starts: dict[str, int] = {} # mutable-ok: per-generation counter
|
||||
self._job_starts: dict[str, int] = {}
|
||||
|
||||
async def _active_jobs(self) -> Mapping[tuple[str, str], tuple[ActiveShadowEvalJob, ...]]:
|
||||
"""Active jobs by (target_type, target_id), cache-first. A target holds at most
|
||||
|
|
@ -1278,8 +1278,8 @@ class ShadowEvalLogger(CustomLogger):
|
|||
router: Final = self._router_provider()
|
||||
if router is None:
|
||||
return _CallFailure("no router configured on this pod")
|
||||
shadow_metadata: Final[dict[str, object]] = ( # mutable-ok: router writes its routing decision back
|
||||
sanitized_forwardable_call_metadata(parent_metadata, SHADOW_EVAL_ROUTER_CALL_ORIGIN)
|
||||
shadow_metadata: Final[dict[str, object]] = sanitized_forwardable_call_metadata(
|
||||
parent_metadata, SHADOW_EVAL_ROUTER_CALL_ORIGIN
|
||||
)
|
||||
try:
|
||||
response: Final = await router.acompletion(
|
||||
|
|
|
|||
|
|
@ -1834,7 +1834,7 @@ class WebSearchInterceptionLogger(CustomLogger):
|
|||
for tool_call in tool_calls:
|
||||
# Handle both Anthropic-style input and OpenAI-style function.arguments
|
||||
query = None
|
||||
tool_args: dict[str, object] | None = None # mutable-ok: the tool call's own arguments dict
|
||||
tool_args: dict[str, object] | None = None
|
||||
if "input" in tool_call and isinstance(tool_call["input"], dict):
|
||||
tool_args = tool_call["input"]
|
||||
query = tool_args.get("query")
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ _WEB_SEARCH_TOOL_DESCRIPTION: Final = (
|
|||
)
|
||||
|
||||
|
||||
def _web_search_input_schema() -> dict[str, object]: # mutable-ok: plain-dict tool shape, as the get_* builders
|
||||
def _web_search_input_schema() -> dict[str, object]:
|
||||
"""
|
||||
JSON schema for the web search tool's input, shared by every tool format.
|
||||
|
||||
|
|
|
|||
|
|
@ -126,9 +126,7 @@ class InMemoryBackgroundSettlementStore:
|
|||
registration relies on.
|
||||
"""
|
||||
|
||||
_rows: dict[str, PendingBackgroundInteraction | None] = field( # mutable-ok: the registry every settler shares
|
||||
default_factory=dict
|
||||
)
|
||||
_rows: dict[str, PendingBackgroundInteraction | None] = field(default_factory=dict)
|
||||
|
||||
async def register(self, pending: PendingBackgroundInteraction) -> None:
|
||||
self._rows[pending.interaction_id] = pending
|
||||
|
|
@ -470,7 +468,7 @@ class _ActiveBackgroundPoll:
|
|||
context: BackgroundInteractionPollContext
|
||||
|
||||
|
||||
_ACTIVE_POLLS: Final[dict[str, _ActiveBackgroundPoll]] = {} # mutable-ok: asyncio needs strong refs to poll tasks
|
||||
_ACTIVE_POLLS: Final[dict[str, _ActiveBackgroundPoll]] = {}
|
||||
|
||||
|
||||
def _discard_poll(interaction_id: str, task: "asyncio.Task[SettlementOutcome | None]") -> None:
|
||||
|
|
|
|||
|
|
@ -579,8 +579,8 @@ def safe_deep_copy(data):
|
|||
|
||||
|
||||
def independent_snapshot(
|
||||
data: dict, # mutable-ok: caller-defined request-payload shape
|
||||
) -> dict: # mutable-ok: caller-defined request-payload shape
|
||||
data: dict,
|
||||
) -> dict:
|
||||
"""
|
||||
A copy of ``data`` whose top-level keys are deep-copied independently
|
||||
where possible -- always attempted, regardless of
|
||||
|
|
@ -771,13 +771,13 @@ _NO_HEADERS: Final[Mapping[str, object]] = MappingProxyType({})
|
|||
|
||||
|
||||
class _CarriesHiddenParams(Protocol):
|
||||
_hidden_params: dict[str, object] # mutable-ok: the responses billed here keep hidden params in a plain dict
|
||||
_hidden_params: dict[str, object]
|
||||
|
||||
@property
|
||||
def hidden_params(self) -> dict[str, object]: ... # mutable-ok: API requires mutation
|
||||
def hidden_params(self) -> dict[str, object]: ...
|
||||
|
||||
@hidden_params.setter
|
||||
def hidden_params(self, hidden_params: dict[str, object]) -> None: ... # mutable-ok: API requires mutation
|
||||
def hidden_params(self, hidden_params: dict[str, object]) -> None: ...
|
||||
|
||||
|
||||
def set_response_cost_in_hidden_params(response: _CarriesHiddenParams, cost: float | None) -> None:
|
||||
|
|
@ -786,7 +786,7 @@ def set_response_cost_in_hidden_params(response: _CarriesHiddenParams, cost: flo
|
|||
return
|
||||
hidden_params: Final = response.hidden_params
|
||||
additional_headers: Final[object] = hidden_params.get("additional_headers")
|
||||
merged: Final[dict[str, object]] = { # mutable-ok: assigned into the plain-dict hidden params
|
||||
merged: Final[dict[str, object]] = {
|
||||
**(additional_headers if isinstance(additional_headers, Mapping) else _NO_HEADERS),
|
||||
RESPONSE_COST_HEADER: cost,
|
||||
}
|
||||
|
|
@ -802,8 +802,8 @@ def set_provider_response_headers_in_hidden_params(
|
|||
) -> None:
|
||||
hidden_params: Final = response.hidden_params
|
||||
existing_additional_headers: Final[object] = hidden_params.get("additional_headers")
|
||||
raw_headers: Final[dict[str, str]] = dict(headers) # mutable-ok: stored as the plain-dict hidden param
|
||||
additional_headers: Final[dict[str, object]] = { # mutable-ok: assigned into the plain-dict hidden params
|
||||
raw_headers: Final[dict[str, str]] = dict(headers)
|
||||
additional_headers: Final[dict[str, object]] = {
|
||||
**process_response_headers(raw_headers),
|
||||
**(existing_additional_headers if isinstance(existing_additional_headers, Mapping) else _NO_HEADERS),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -213,7 +213,7 @@ def mark_litellm_import_complete() -> None:
|
|||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class ModelCostMapReloaded:
|
||||
model_cost_map: dict # mutable-ok: adopted as litellm.model_cost, whose consumer contract is a plain mutable dict
|
||||
model_cost_map: dict
|
||||
revision: str | None = None
|
||||
etag: str | None = None
|
||||
|
||||
|
|
@ -557,7 +557,7 @@ def _finalize_loaded_model_cost_map(loaded: ModelCostMapReloaded) -> ModelCostMa
|
|||
|
||||
|
||||
def adopt_model_cost_map(
|
||||
new_model_cost_map: dict, # mutable-ok: public API preserves the mutable cost-map contract
|
||||
new_model_cost_map: dict,
|
||||
) -> int:
|
||||
import litellm
|
||||
from litellm import utils
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@ def sanitize_user_api_key_auth(auth: object) -> object:
|
|||
return auth
|
||||
|
||||
|
||||
def _sanitized(parent_metadata: Mapping[str, object]) -> dict[str, object]: # mutable-ok: SDK metadata kwarg
|
||||
def _sanitized(parent_metadata: Mapping[str, object]) -> dict[str, object]:
|
||||
return {
|
||||
k: sanitize_user_api_key_auth(v) if k == _USER_API_KEY_AUTH_KEY else v
|
||||
for k, v in parent_metadata.items()
|
||||
|
|
@ -131,7 +131,7 @@ def _sanitized(parent_metadata: Mapping[str, object]) -> dict[str, object]: # m
|
|||
def forwarded_internal_call_metadata(
|
||||
parent_metadata: Mapping[str, object] | None,
|
||||
call_origin: InternalCallOrigin,
|
||||
) -> dict[str, object]: # mutable-ok: SDK metadata kwarg
|
||||
) -> dict[str, object]:
|
||||
"""Parent metadata, minus its budget reservation, stamped with the sub-call's origin.
|
||||
|
||||
For sub-calls made inside the parent request (classifier, embeddings), where the
|
||||
|
|
@ -158,7 +158,7 @@ def effective_turn_off_message_logging(request_kwargs: Mapping[str, object] | No
|
|||
def sanitized_forwardable_call_metadata(
|
||||
parent_metadata: Mapping[str, object],
|
||||
call_origin: InternalCallOrigin,
|
||||
) -> dict[str, object]: # mutable-ok: SDK metadata kwarg
|
||||
) -> dict[str, object]:
|
||||
"""Just the caller's identity, stamped with the sub-call's origin.
|
||||
|
||||
For sub-calls detached from the parent request (shadow eval), which outlive it and
|
||||
|
|
|
|||
|
|
@ -1107,7 +1107,7 @@ class Logging(LiteLLMLoggingBaseClass):
|
|||
prompt_management_logger: CustomLogger | None = None,
|
||||
prompt_label: str | None = None,
|
||||
prompt_version: int | None = None,
|
||||
request_kwargs: dict[str, object] | None = None, # mutable-ok: marker stamped into live request kwargs
|
||||
request_kwargs: dict[str, object] | None = None,
|
||||
injected_for_every_deployment: bool = False,
|
||||
) -> tuple[str, list[AllMessageValues], dict]:
|
||||
from litellm.integrations.anthropic_cache_control_hook import AnthropicCacheControlHook
|
||||
|
|
@ -1158,7 +1158,7 @@ class Logging(LiteLLMLoggingBaseClass):
|
|||
tools: list[dict] | None = None,
|
||||
prompt_label: str | None = None,
|
||||
prompt_version: int | None = None,
|
||||
request_kwargs: dict[str, object] | None = None, # mutable-ok: marker stamped into live request kwargs
|
||||
request_kwargs: dict[str, object] | None = None,
|
||||
injected_for_every_deployment: bool = False,
|
||||
) -> tuple[str, list[AllMessageValues], dict]:
|
||||
from litellm.integrations.anthropic_cache_control_hook import AnthropicCacheControlHook
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ def default_router_provider() -> Router | None:
|
|||
return llm_router
|
||||
|
||||
|
||||
def parse_json_verdict(raw: str) -> dict[str, object]: # mutable-ok: plain parsed-JSON payload
|
||||
def parse_json_verdict(raw: str) -> dict[str, object]:
|
||||
"""Parse a judge's JSON verdict, tolerating markdown fences and surrounding prose."""
|
||||
text = raw.strip() # rebind-ok: progressively narrowed to the JSON payload
|
||||
fenced: Final = JSON_FENCE_RE.search(text)
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ class LoggingWorker:
|
|||
self._queue: asyncio.Queue[LoggingTask] | None = None
|
||||
self._worker_task: asyncio.Task | None = None
|
||||
self._running_tasks: set[asyncio.Task] = set()
|
||||
self._dequeued_tasks: dict[int, LoggingTask] = {} # mutable-ok: refs so flush can rescue never-started tasks
|
||||
self._dequeued_tasks: dict[int, LoggingTask] = {}
|
||||
self._sem: asyncio.Semaphore | None = None
|
||||
self._bound_loop: asyncio.AbstractEventLoop | None = None
|
||||
self._last_aggressive_clear_time: float = 0.0
|
||||
|
|
|
|||
|
|
@ -1212,7 +1212,7 @@ def _mergeable_branch(
|
|||
branch: object,
|
||||
seen_refs: frozenset[str],
|
||||
depth: int,
|
||||
expanded_refs: dict[str, Mapping[str, object] | None], # mutable-ok: per-call memo bounding repeated $ref work
|
||||
expanded_refs: dict[str, Mapping[str, object] | None],
|
||||
) -> Mapping[str, object] | None:
|
||||
if not isinstance(branch, dict) or depth > _MAX_SCHEMA_FLATTEN_DEPTH:
|
||||
return None
|
||||
|
|
@ -1245,7 +1245,7 @@ def _flatten_schema_against_root(
|
|||
root: Mapping[str, object],
|
||||
seen_refs: frozenset[str],
|
||||
depth: int,
|
||||
expanded_refs: dict[str, Mapping[str, object] | None], # mutable-ok: per-call memo bounding repeated $ref work
|
||||
expanded_refs: dict[str, Mapping[str, object] | None],
|
||||
) -> Mapping[str, object]:
|
||||
raw_branch_groups: Final = tuple(
|
||||
(
|
||||
|
|
@ -1377,7 +1377,7 @@ def drop_lookaround_regex_patterns(schema: Mapping[str, object]) -> Mapping[str,
|
|||
def _schema_without_rejected_regex(
|
||||
schema: Mapping[str, object], rejected: Callable[[str], bool]
|
||||
) -> Mapping[str, object]:
|
||||
rebuilt: dict[int, Mapping[str, object]] = {} # mutable-ok: per-call memo of rewritten nodes, deepest level first
|
||||
rebuilt: dict[int, Mapping[str, object]] = {}
|
||||
for level in reversed(tuple(islice(_schema_levels(schema), _MAX_SCHEMA_NESTING))):
|
||||
rebuilt.update(
|
||||
(id(node), rewritten)
|
||||
|
|
|
|||
|
|
@ -83,9 +83,7 @@ def get_stable_session_id(litellm_params: object | None) -> str | None:
|
|||
return None
|
||||
|
||||
|
||||
def add_provider_affinity_header(
|
||||
headers: Mapping[str, object], litellm_params: object | None
|
||||
) -> dict[str, object]: # mutable-ok: downstream handlers add auth and signing headers
|
||||
def add_provider_affinity_header(headers: Mapping[str, object], litellm_params: object | None) -> dict[str, object]:
|
||||
header_name: Final = _get_provider_affinity_header_name(litellm_params)
|
||||
if header_name is None or any(key.lower() == header_name.lower() for key in headers):
|
||||
return dict(headers)
|
||||
|
|
|
|||
|
|
@ -194,9 +194,7 @@ def mask_credentials_in_payload(data: object) -> object:
|
|||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class _PayloadWalker:
|
||||
_memo: dict[tuple[int, bool], tuple[object, object]] = field( # mutable-ok: memo of one walk, pins each keyed node
|
||||
default_factory=dict
|
||||
)
|
||||
_memo: dict[tuple[int, bool], tuple[object, object]] = field(default_factory=dict)
|
||||
|
||||
def walk(self, node: object, key_is_sensitive: bool, depth: int) -> object:
|
||||
if not isinstance(node, (Mapping, list, tuple, BaseModel)):
|
||||
|
|
|
|||
|
|
@ -208,11 +208,11 @@ def _provider_hidden_params(
|
|||
|
||||
class CustomStreamWrapper:
|
||||
@property
|
||||
def hidden_params(self) -> dict[str, object]: # mutable-ok: API requires mutation
|
||||
def hidden_params(self) -> dict[str, object]:
|
||||
return self._hidden_params
|
||||
|
||||
@hidden_params.setter
|
||||
def hidden_params(self, hidden_params: dict[str, object]) -> None: # mutable-ok: API requires mutation
|
||||
def hidden_params(self, hidden_params: dict[str, object]) -> None:
|
||||
self._hidden_params = hidden_params
|
||||
|
||||
def __init__(
|
||||
|
|
|
|||
|
|
@ -263,13 +263,13 @@ class HuggingFaceTokenizer:
|
|||
def id_to_token(self, id: int) -> str | None:
|
||||
return self._native.id_to_token(id)
|
||||
|
||||
def get_vocab(self, with_added_tokens: bool = True) -> dict[str, int]: # mutable-ok: [LIT001] SDK return type
|
||||
def get_vocab(self, with_added_tokens: bool = True) -> dict[str, int]:
|
||||
return self._native.get_vocab(with_added_tokens)
|
||||
|
||||
def get_vocab_size(self, with_added_tokens: bool = True) -> int:
|
||||
return self._native.get_vocab_size(with_added_tokens)
|
||||
|
||||
def get_added_tokens_decoder(self) -> dict[int, AddedToken]: # mutable-ok: [LIT001] SDK return type
|
||||
def get_added_tokens_decoder(self) -> dict[int, AddedToken]:
|
||||
return {
|
||||
token_id: AddedToken(
|
||||
content, single_word=single_word, lstrip=lstrip, rstrip=rstrip, normalized=normalized, special=special
|
||||
|
|
@ -288,11 +288,11 @@ class HuggingFaceTokenizer:
|
|||
return self._native.num_special_tokens_to_add(is_pair)
|
||||
|
||||
@property
|
||||
def padding(self) -> dict[str, object] | None: # mutable-ok: [LIT001] SDK return type
|
||||
def padding(self) -> dict[str, object] | None:
|
||||
return self._native.padding()
|
||||
|
||||
@property
|
||||
def truncation(self) -> dict[str, object] | None: # mutable-ok: [LIT001] SDK return type
|
||||
def truncation(self) -> dict[str, object] | None:
|
||||
return self._native.truncation()
|
||||
|
||||
@property
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ class AnthropicBatchesHandler:
|
|||
timeout: float | httpx.Timeout,
|
||||
max_retries: int | None,
|
||||
logging_obj: LiteLLMLoggingObj | None = None,
|
||||
litellm_params: dict | None = None, # mutable-ok: handed straight to validate_environment
|
||||
litellm_params: dict | None = None,
|
||||
) -> LiteLLMBatch:
|
||||
"""
|
||||
Async: Retrieve a batch from Anthropic.
|
||||
|
|
@ -131,7 +131,7 @@ class AnthropicBatchesHandler:
|
|||
timeout: float | httpx.Timeout,
|
||||
max_retries: int | None,
|
||||
logging_obj: LiteLLMLoggingObj | None = None,
|
||||
litellm_params: dict | None = None, # mutable-ok: handed straight to validate_environment
|
||||
litellm_params: dict | None = None,
|
||||
) -> LiteLLMBatch | Coroutine[Any, Any, LiteLLMBatch]:
|
||||
"""
|
||||
Retrieve a batch from Anthropic.
|
||||
|
|
|
|||
|
|
@ -719,7 +719,7 @@ class AnthropicMessagesHandler(BaseTranslation):
|
|||
@staticmethod
|
||||
def _openai_system_message_to_anthropic(
|
||||
message: Mapping[str, object],
|
||||
) -> dict[str, object] | None: # mutable-ok: API message payload
|
||||
) -> dict[str, object] | None:
|
||||
"""Convert an OpenAI system message to the client's Anthropic-shaped entry."""
|
||||
content: Final = message.get("content")
|
||||
if isinstance(content, str):
|
||||
|
|
@ -733,7 +733,7 @@ class AnthropicMessagesHandler(BaseTranslation):
|
|||
text = block.get("text")
|
||||
if not isinstance(text, str) or not text:
|
||||
continue
|
||||
anthropic_block: dict[str, object] = { # mutable-ok: API message payload
|
||||
anthropic_block: dict[str, object] = {
|
||||
"type": "text",
|
||||
"text": text,
|
||||
}
|
||||
|
|
@ -745,7 +745,7 @@ class AnthropicMessagesHandler(BaseTranslation):
|
|||
|
||||
@staticmethod
|
||||
def _fold_leading_systems_into_top_level(
|
||||
data: dict[str, object], # mutable-ok: API message payload
|
||||
data: dict[str, object],
|
||||
leading_systems: Sequence[object],
|
||||
include_existing_system: bool,
|
||||
) -> None:
|
||||
|
|
@ -826,7 +826,7 @@ class AnthropicMessagesHandler(BaseTranslation):
|
|||
|
||||
@staticmethod
|
||||
def _write_back_structured_messages(
|
||||
data: dict, # mutable-ok: API message payload
|
||||
data: dict,
|
||||
structured_messages: list, # mutable-ok: API message payload
|
||||
hoisted_system_message: object = None,
|
||||
preserve_system_messages: bool = False,
|
||||
|
|
@ -1070,7 +1070,7 @@ class AnthropicMessagesHandler(BaseTranslation):
|
|||
|
||||
async def _apply_guardrail_responses_to_input(
|
||||
self,
|
||||
data: dict[str, object], # mutable-ok: API message payload
|
||||
data: dict[str, object],
|
||||
responses: Sequence[str],
|
||||
scanned: tuple[ScannedText, ...],
|
||||
) -> None:
|
||||
|
|
|
|||
|
|
@ -369,7 +369,7 @@ class AnthropicChatCompletion(BaseLLM):
|
|||
|
||||
transform_params: Final = {**optional_params, "is_vertex_request": is_vertex_request}
|
||||
|
||||
def finish_request(request_data: dict) -> tuple[dict, dict]: # mutable-ok: rewritten in place downstream
|
||||
def finish_request(request_data: dict) -> tuple[dict, dict]:
|
||||
"""Filter beta headers and emit pre_call, returning `(headers, data)`.
|
||||
|
||||
The pair stays mutable because the streaming path rewrites it in
|
||||
|
|
@ -586,7 +586,7 @@ class ModelResponseIterator:
|
|||
# Accumulate web_search_tool_result blocks for multi-turn reconstruction
|
||||
# See: https://github.com/BerriAI/litellm/issues/17737
|
||||
self.web_search_results: list[dict[str, object]] = []
|
||||
self._web_search_calls: dict[str, object] = {} # mutable-ok: provider call state by id
|
||||
self._web_search_calls: dict[str, object] = {}
|
||||
|
||||
# Accumulate compaction blocks for multi-turn reconstruction
|
||||
self.compaction_blocks: list[dict[str, object]] = []
|
||||
|
|
|
|||
|
|
@ -493,7 +493,7 @@ class AnthropicConfig(AnthropicModelInfo, BaseConfig):
|
|||
def maybe_drop_speed_param(
|
||||
cls,
|
||||
model: str,
|
||||
optional_params: dict[str, object], # mutable-ok: mirrors override contract
|
||||
optional_params: dict[str, object],
|
||||
drop_params: bool,
|
||||
custom_llm_provider: str | None = None,
|
||||
) -> None:
|
||||
|
|
@ -1949,10 +1949,10 @@ class AnthropicConfig(AnthropicModelInfo, BaseConfig):
|
|||
self,
|
||||
model: str,
|
||||
messages: list[AllMessageValues], # mutable-ok: BaseConfig signature
|
||||
optional_params: dict[str, object], # mutable-ok: BaseConfig signature
|
||||
litellm_params: dict[str, object], # mutable-ok: BaseConfig signature
|
||||
headers: dict[str, object], # mutable-ok: BaseConfig signature
|
||||
) -> dict[str, object]: # mutable-ok: BaseConfig signature
|
||||
optional_params: dict[str, object],
|
||||
litellm_params: dict[str, object],
|
||||
headers: dict[str, object],
|
||||
) -> dict[str, object]:
|
||||
return self.transform_request(
|
||||
model=model,
|
||||
messages=await async_inline_remote_media(messages, should_inline=self.inlines_remote_media),
|
||||
|
|
|
|||
|
|
@ -667,7 +667,7 @@ class AnthropicModelInfo(BaseLLMModelInfo):
|
|||
@classmethod
|
||||
def apply_sampling_param(
|
||||
cls,
|
||||
optional_params: dict[str, object], # mutable-ok: mirrors override contract
|
||||
optional_params: dict[str, object],
|
||||
model: str,
|
||||
param: str,
|
||||
value: object,
|
||||
|
|
@ -892,7 +892,7 @@ class AnthropicModelInfo(BaseLLMModelInfo):
|
|||
@staticmethod
|
||||
def maybe_drop_disabled_thinking(
|
||||
model: str,
|
||||
optional_params: MutableMapping[str, object], # mutable-ok: in-place out-param, as in _maybe_drop_speed_param
|
||||
optional_params: MutableMapping[str, object],
|
||||
custom_llm_provider: str,
|
||||
) -> None:
|
||||
"""Omit ``thinking={'type': 'disabled'}`` for always-on-thinking models
|
||||
|
|
@ -912,7 +912,7 @@ class AnthropicModelInfo(BaseLLMModelInfo):
|
|||
@staticmethod
|
||||
def translate_legacy_thinking_for_adaptive_model(
|
||||
model: str,
|
||||
optional_params: MutableMapping[str, object], # mutable-ok: in-place out-param like the sibling helpers
|
||||
optional_params: MutableMapping[str, object],
|
||||
custom_llm_provider: str,
|
||||
) -> None:
|
||||
"""Translate legacy ``thinking.type=enabled`` to adaptive for the
|
||||
|
|
@ -1634,7 +1634,7 @@ def strip_thinking_blocks_from_anthropic_messages(messages: Sequence[object]) ->
|
|||
return out
|
||||
|
||||
|
||||
def _without_encrypted_reasoning_blocks(message: dict) -> dict | None: # mutable-ok: Anthropic message payload shape
|
||||
def _without_encrypted_reasoning_blocks(message: dict) -> dict | None:
|
||||
if not isinstance(message, Mapping):
|
||||
return message
|
||||
content: Final = message.get("content")
|
||||
|
|
@ -1649,7 +1649,7 @@ def _without_encrypted_reasoning_blocks(message: dict) -> dict | None: # mutabl
|
|||
|
||||
|
||||
def strip_encrypted_reasoning_blocks_from_anthropic_messages(
|
||||
messages: Sequence[dict], # mutable-ok: Anthropic message payload shape
|
||||
messages: Sequence[dict],
|
||||
) -> list[dict]: # mutable-ok: AnthropicMessagesRequest.messages is typed list[dict]
|
||||
"""
|
||||
Drop thinking / redacted_thinking blocks that carry another provider's encrypted
|
||||
|
|
@ -1999,14 +1999,14 @@ def strip_provider_specific_fields_from_anthropic_messages(
|
|||
return [_strip_provider_specific_fields_in_message(m) for m in messages]
|
||||
|
||||
|
||||
def _normalized_cache_control(cache_control: object) -> dict[str, str] | None: # mutable-ok: JSON wire format
|
||||
def _normalized_cache_control(cache_control: object) -> dict[str, str] | None:
|
||||
if not isinstance(cache_control, Mapping):
|
||||
return None
|
||||
cache_type: Final = cache_control.get("type")
|
||||
return {"type": cache_type if isinstance(cache_type, str) else "ephemeral"}
|
||||
|
||||
|
||||
def _with_portable_cache_control(block: Mapping[str, object]) -> dict[str, object]: # mutable-ok: JSON wire format
|
||||
def _with_portable_cache_control(block: Mapping[str, object]) -> dict[str, object]:
|
||||
if "cache_control" not in block:
|
||||
return dict(block)
|
||||
normalized: Final = _normalized_cache_control(block["cache_control"])
|
||||
|
|
@ -2062,7 +2062,7 @@ def _with_portable_cache_control_in_scoped_value(key: str, value: object) -> obj
|
|||
|
||||
def normalize_cache_control_in_anthropic_payload(
|
||||
payload: Mapping[str, object],
|
||||
) -> dict[str, object]: # mutable-ok: JSON wire format
|
||||
) -> dict[str, object]:
|
||||
"""
|
||||
Return a copy of an Anthropic /v1/messages payload with every
|
||||
``cache_control`` entry reduced to ``{"type": <its type, or "ephemeral">}``
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ class AnthropicCountTokensConfig:
|
|||
tools: list[dict[str, JsonValue]] | None = None,
|
||||
system: JsonValue = None,
|
||||
optional_params: Mapping[str, JsonValue] | None = None,
|
||||
) -> dict[str, JsonValue]: # mutable-ok: provider transport requires JSON dictionaries
|
||||
) -> dict[str, JsonValue]:
|
||||
"""
|
||||
Transform request to Anthropic CountTokens format.
|
||||
|
||||
|
|
|
|||
|
|
@ -111,14 +111,14 @@ class AnthropicFilesConfig(BaseFilesConfig):
|
|||
|
||||
async def avalidate_environment(
|
||||
self,
|
||||
headers: dict, # mutable-ok: mirrors the sync validate_environment contract this overrides
|
||||
headers: dict,
|
||||
model: str,
|
||||
messages: list, # mutable-ok: mirrors the sync validate_environment contract this overrides
|
||||
optional_params: dict, # mutable-ok: mirrors the sync validate_environment contract this overrides
|
||||
litellm_params: dict, # mutable-ok: mirrors the sync validate_environment contract this overrides
|
||||
optional_params: dict,
|
||||
litellm_params: dict,
|
||||
api_key: str | None = None,
|
||||
api_base: str | None = None,
|
||||
) -> dict: # mutable-ok: mirrors the sync validate_environment contract this overrides
|
||||
) -> dict:
|
||||
"""Async counterpart of validate_environment: the WIF tier can block on a token
|
||||
exchange POST, so async callers await it off the event loop."""
|
||||
params_mapping, resolved_api_base = self._resolve_params(litellm_params, api_base)
|
||||
|
|
@ -136,7 +136,7 @@ class AnthropicFilesConfig(BaseFilesConfig):
|
|||
return params_mapping, resolved_api_base
|
||||
|
||||
@staticmethod
|
||||
def _finalize_headers(headers: dict, auth_header: Mapping[str, str] | None) -> dict: # mutable-ok: out-param
|
||||
def _finalize_headers(headers: dict, auth_header: Mapping[str, str] | None) -> dict:
|
||||
if auth_header is None:
|
||||
raise ValueError(
|
||||
"Anthropic API key is required. Set ANTHROPIC_API_KEY or ANTHROPIC_AUTH_TOKEN environment variable or pass api_key parameter."
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ class AnthropicMessagesStreamCacheWriter:
|
|||
self.caching_handler = caching_handler
|
||||
self.collected_chunks: list[bytes] = [] # mutable-ok: rebuilding a tuple per SSE chunk is quadratic
|
||||
self.persisted = False
|
||||
self._hidden_params: dict[str, object] = dict( # mutable-ok: callers stamp cache_key in here
|
||||
self._hidden_params: dict[str, object] = dict(
|
||||
stream.hidden_params if isinstance(stream, AnthropicMessagesStreamingResponse) else _EMPTY_MAPPING
|
||||
)
|
||||
|
||||
|
|
@ -139,7 +139,7 @@ class CachedAnthropicMessagesStreamIterator(BaseAnthropicMessagesStreamingIterat
|
|||
self.chunks: Final[tuple[bytes, ...]] = tuple(event.encode("utf-8") for event in events)
|
||||
self.current_index = 0
|
||||
self.logged = False
|
||||
self._hidden_params: dict[str, object] = {"cache_hit": True} # mutable-ok: callers stamp cache_key in here
|
||||
self._hidden_params: dict[str, object] = {"cache_hit": True}
|
||||
litellm_logging_obj.model_call_details["cache_hit"] = True
|
||||
|
||||
def __aiter__(self) -> "CachedAnthropicMessagesStreamIterator":
|
||||
|
|
|
|||
|
|
@ -290,14 +290,14 @@ class AnthropicMessagesConfig(BaseAnthropicMessagesConfig):
|
|||
|
||||
async def avalidate_anthropic_messages_environment(
|
||||
self,
|
||||
headers: dict, # mutable-ok: mirrors the sync validate_anthropic_messages_environment contract
|
||||
headers: dict,
|
||||
model: str,
|
||||
messages: list[Any], # mutable-ok: mirrors the sync validate_anthropic_messages_environment contract
|
||||
optional_params: dict, # mutable-ok: mirrors the sync validate_anthropic_messages_environment contract
|
||||
litellm_params: dict, # mutable-ok: mirrors the sync validate_anthropic_messages_environment contract
|
||||
optional_params: dict,
|
||||
litellm_params: dict,
|
||||
api_key: str | None = None,
|
||||
api_base: str | None = None,
|
||||
) -> tuple[dict, str | None]: # mutable-ok: mirrors the sync validate_anthropic_messages_environment contract
|
||||
) -> tuple[dict, str | None]:
|
||||
if type(self).validate_anthropic_messages_environment is not (
|
||||
AnthropicMessagesConfig.validate_anthropic_messages_environment
|
||||
):
|
||||
|
|
@ -342,7 +342,7 @@ class AnthropicMessagesConfig(BaseAnthropicMessagesConfig):
|
|||
return auth_header
|
||||
|
||||
@staticmethod
|
||||
def _apply_env_auth_header(headers: dict, auth_header: Mapping[str, str] | None) -> None: # mutable-ok: out-param
|
||||
def _apply_env_auth_header(headers: dict, auth_header: Mapping[str, str] | None) -> None:
|
||||
if auth_header is None:
|
||||
return
|
||||
merged_beta: Final = merge_anthropic_beta_headers(
|
||||
|
|
@ -362,10 +362,10 @@ class AnthropicMessagesConfig(BaseAnthropicMessagesConfig):
|
|||
|
||||
def _finalize_messages_headers(
|
||||
self,
|
||||
headers: dict, # mutable-ok: out-param
|
||||
optional_params: dict, # mutable-ok: out-param
|
||||
headers: dict,
|
||||
optional_params: dict,
|
||||
messages: list[object], # mutable-ok: mirrors the validate_anthropic_messages_environment contract
|
||||
) -> dict: # mutable-ok: out-param
|
||||
) -> dict:
|
||||
if "anthropic-version" not in headers:
|
||||
headers["anthropic-version"] = DEFAULT_ANTHROPIC_API_VERSION
|
||||
if "content-type" not in headers:
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ class LiteLLMAnthropicToResponsesAPIAdapter:
|
|||
@staticmethod
|
||||
def _translate_anthropic_document_block_to_file_part(
|
||||
block: Mapping[str, object],
|
||||
) -> dict[str, str] | None: # mutable-ok: API message payload
|
||||
) -> dict[str, str] | None:
|
||||
"""Convert an Anthropic document block to a Responses input_file part."""
|
||||
raw_source: Final = block.get("source")
|
||||
if not isinstance(raw_source, Mapping):
|
||||
|
|
@ -130,7 +130,7 @@ class LiteLLMAnthropicToResponsesAPIAdapter:
|
|||
@staticmethod
|
||||
def _tool_result_output_value(
|
||||
output_text: str,
|
||||
file_parts: tuple[dict[str, str], ...], # mutable-ok: json content parts
|
||||
file_parts: tuple[dict[str, str], ...],
|
||||
) -> str | list[dict[str, str]]: # mutable-ok: API message payload
|
||||
"""Plain string output, or a part list when document file parts are present."""
|
||||
if not file_parts:
|
||||
|
|
@ -165,7 +165,7 @@ class LiteLLMAnthropicToResponsesAPIAdapter:
|
|||
cls,
|
||||
summary: Iterable[object],
|
||||
encrypted_content: object,
|
||||
) -> dict[str, object] | None: # mutable-ok: API message payload
|
||||
) -> dict[str, object] | None:
|
||||
"""The one Anthropic block for a Responses reasoning item.
|
||||
|
||||
The item's encrypted reasoning rides the block's opaque field (`signature`, or
|
||||
|
|
@ -192,9 +192,7 @@ class LiteLLMAnthropicToResponsesAPIAdapter:
|
|||
return "thinking" if block.get("type") in ("thinking", "redacted_thinking") else f"block:{index}"
|
||||
|
||||
@classmethod
|
||||
def _assistant_group_to_input_items(
|
||||
cls, group: tuple[Mapping[str, object], ...]
|
||||
) -> tuple[dict[str, object], ...]: # mutable-ok: API message payload
|
||||
def _assistant_group_to_input_items(cls, group: tuple[Mapping[str, object], ...]) -> tuple[dict[str, object], ...]:
|
||||
first: Final = group[0]
|
||||
btype: Final = first.get("type")
|
||||
if btype in ("thinking", "redacted_thinking"):
|
||||
|
|
|
|||
|
|
@ -425,7 +425,7 @@ def _digest(value: object) -> str:
|
|||
).hexdigest()
|
||||
|
||||
|
||||
def _json_object(value: object) -> dict[str, JsonValue]: # mutable-ok: JSON serialization requires a dictionary
|
||||
def _json_object(value: object) -> dict[str, JsonValue]:
|
||||
return _JSON_OBJECT.validate_python(value)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1269,7 +1269,7 @@ class AzureChatCompletion(BaseAzureLLM, BaseLLM):
|
|||
if not isinstance(max_retries, int):
|
||||
raise AzureOpenAIError(status_code=422, message="max retries must be an int")
|
||||
|
||||
auth_params: Final[dict[str, object]] = {**(litellm_params or {})} # mutable-ok: SDK init takes a dict
|
||||
auth_params: Final[dict[str, object]] = {**(litellm_params or {})}
|
||||
if azure_ad_token is not None:
|
||||
auth_params["azure_ad_token"] = azure_ad_token
|
||||
if azure_ad_token_provider is not None:
|
||||
|
|
|
|||
|
|
@ -789,9 +789,9 @@ class BaseAzureLLM(BaseOpenAILLM):
|
|||
@classmethod
|
||||
def base_validate_azure_environment(
|
||||
cls,
|
||||
headers: dict[str, str], # mutable-ok: mirrors override contract
|
||||
headers: dict[str, str],
|
||||
litellm_params: GenericLiteLLMParams | None,
|
||||
) -> dict[str, str]: # mutable-ok: mirrors override contract
|
||||
) -> dict[str, str]:
|
||||
return cls._base_validate_azure_environment(headers, litellm_params)
|
||||
|
||||
@staticmethod
|
||||
|
|
|
|||
|
|
@ -279,11 +279,11 @@ class BingGroundingSearchConfig(BaseSearchConfig):
|
|||
|
||||
def validate_environment(
|
||||
self,
|
||||
headers: dict[str, str], # mutable-ok: BaseSearchConfig.validate_environment signature
|
||||
headers: dict[str, str],
|
||||
api_key: str | None = None,
|
||||
api_base: str | None = None,
|
||||
**kwargs: object, # kwargs-ok: BaseSearchConfig.validate_environment signature
|
||||
) -> dict[str, str]: # mutable-ok: the http handler passes this straight to httpx as headers
|
||||
) -> dict[str, str]:
|
||||
"""
|
||||
Validate environment and return headers.
|
||||
|
||||
|
|
@ -331,7 +331,7 @@ class BingGroundingSearchConfig(BaseSearchConfig):
|
|||
def get_complete_url(
|
||||
self,
|
||||
api_base: str | None,
|
||||
optional_params: dict[str, object], # mutable-ok: BaseSearchConfig.get_complete_url signature
|
||||
optional_params: dict[str, object],
|
||||
data: dict[str, object] | list[dict[str, object]] | None = None, # mutable-ok: base signature
|
||||
**kwargs: object, # kwargs-ok: BaseSearchConfig.get_complete_url signature
|
||||
) -> str:
|
||||
|
|
@ -349,9 +349,9 @@ class BingGroundingSearchConfig(BaseSearchConfig):
|
|||
def transform_search_request(
|
||||
self,
|
||||
query: str | list[str], # mutable-ok: BaseSearchConfig.transform_search_request signature
|
||||
optional_params: dict[str, object], # mutable-ok: base signature
|
||||
optional_params: dict[str, object],
|
||||
**kwargs: object, # kwargs-ok: BaseSearchConfig.transform_search_request signature
|
||||
) -> dict[str, object]: # mutable-ok: the http handler passes this straight to httpx as the JSON body
|
||||
) -> dict[str, object]:
|
||||
"""
|
||||
Transform Search request to the Foundry Responses API format.
|
||||
|
||||
|
|
@ -429,7 +429,7 @@ class BingGroundingSearchConfig(BaseSearchConfig):
|
|||
self,
|
||||
error_message: str,
|
||||
status_code: int,
|
||||
headers: dict[str, str], # mutable-ok: BaseSearchConfig.get_error_class signature
|
||||
headers: dict[str, str],
|
||||
) -> Exception:
|
||||
detail: Final = _unwrap_error_detail(error_message).rstrip(". ")
|
||||
return BaseLLMException(
|
||||
|
|
|
|||
|
|
@ -187,7 +187,7 @@ class AzureAIAgentsConfig(BaseConfig):
|
|||
def get_agent_id(
|
||||
self,
|
||||
model: str,
|
||||
optional_params: dict[str, object], # mutable-ok: mirrors override contract
|
||||
optional_params: dict[str, object],
|
||||
) -> str:
|
||||
return self._get_agent_id(model, optional_params)
|
||||
|
||||
|
|
|
|||
|
|
@ -91,11 +91,11 @@ class AzureAIStudioConfig(OpenAIConfig):
|
|||
|
||||
def map_openai_params(
|
||||
self,
|
||||
non_default_params: dict[str, object], # mutable-ok: OpenAIConfig.map_openai_params signature
|
||||
optional_params: dict[str, object], # mutable-ok: OpenAIConfig.map_openai_params signature
|
||||
non_default_params: dict[str, object],
|
||||
optional_params: dict[str, object],
|
||||
model: str,
|
||||
drop_params: bool,
|
||||
) -> dict[str, object]: # mutable-ok: OpenAIConfig.map_openai_params signature
|
||||
) -> dict[str, object]:
|
||||
if not azureAIGPT5Config.is_model_gpt_5_model(model):
|
||||
return super().map_openai_params(
|
||||
non_default_params=non_default_params,
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ class AzureAICohereConfig:
|
|||
def transform_request(
|
||||
self,
|
||||
input: list[str], # mutable-ok: mirrors override contract
|
||||
optional_params: dict[str, object], # mutable-ok: mirrors override contract
|
||||
optional_params: dict[str, object],
|
||||
model: str,
|
||||
) -> tuple[ImageEmbeddingRequest, EmbeddingCreateParams, list[int]]: # mutable-ok: mirrors override contract
|
||||
return self._transform_request(input, optional_params, model)
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ class AzureFoundryFluxImageGenerationConfig(GPTImageGenerationConfig):
|
|||
optional_params: Mapping[str, object],
|
||||
model: str,
|
||||
drop_params: bool,
|
||||
) -> dict[str, object]: # mutable-ok: inherited config contract returns a dict
|
||||
) -> dict[str, object]:
|
||||
if not self.is_flux2_model(model):
|
||||
return super().map_openai_params(
|
||||
non_default_params=dict(non_default_params),
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ class AzureAIPassthroughConfig(AzureFoundryModelInfo, BasePassthroughConfig):
|
|||
litellm_params: Mapping[str, object],
|
||||
api_key: str | None = None,
|
||||
api_base: str | None = None,
|
||||
) -> dict[str, str]: # mutable-ok: base class contract returns dict for httpx
|
||||
) -> dict[str, str]:
|
||||
auth_headers: Final = get_azure_ai_auth_headers(
|
||||
api_key=api_key,
|
||||
litellm_params=litellm_params,
|
||||
|
|
|
|||
|
|
@ -43,14 +43,14 @@ class BaseAnthropicMessagesConfig(ABC):
|
|||
|
||||
async def avalidate_anthropic_messages_environment(
|
||||
self,
|
||||
headers: dict, # mutable-ok: mirrors the sync validate_anthropic_messages_environment contract
|
||||
headers: dict,
|
||||
model: str,
|
||||
messages: list[Any], # mutable-ok: mirrors the sync validate_anthropic_messages_environment contract
|
||||
optional_params: dict, # mutable-ok: mirrors the sync validate_anthropic_messages_environment contract
|
||||
litellm_params: dict, # mutable-ok: mirrors the sync validate_anthropic_messages_environment contract
|
||||
optional_params: dict,
|
||||
litellm_params: dict,
|
||||
api_key: str | None = None,
|
||||
api_base: str | None = None,
|
||||
) -> tuple[dict, str | None]: # mutable-ok: mirrors the sync validate_anthropic_messages_environment contract
|
||||
) -> tuple[dict, str | None]:
|
||||
"""Async counterpart used by the async handler. The default delegates to the
|
||||
sync implementation; providers whose sync path can block the event loop
|
||||
(e.g. a WIF token exchange) override this."""
|
||||
|
|
|
|||
|
|
@ -653,7 +653,7 @@ class JwtBearerTokenExchangeEngine:
|
|||
self._shared_store: Final = shared_store
|
||||
self._wall_clock: Final = wall_clock
|
||||
self._lock: Final = threading.Lock()
|
||||
self._entries: Final[dict[str, _Entry]] = {} # mutable-ok: engine-owned map guarded by _lock
|
||||
self._entries: Final[dict[str, _Entry]] = {}
|
||||
|
||||
def get_token(self, spec: TokenExchangeSpec) -> ExchangeResult:
|
||||
"""A follower whose leader published nothing re-classifies rather than recursing, so a
|
||||
|
|
|
|||
|
|
@ -112,7 +112,7 @@ class BaseModelResponseIterator:
|
|||
def string_to_dict_parser(
|
||||
cls,
|
||||
str_line: str,
|
||||
) -> dict[str, object] | None: # mutable-ok: mirrors override contract
|
||||
) -> dict[str, object] | None:
|
||||
return cls._string_to_dict_parser(str_line)
|
||||
|
||||
def _handle_string_chunk(self, str_line: str) -> GenericStreamingChunk | ModelResponseStream:
|
||||
|
|
|
|||
|
|
@ -148,9 +148,9 @@ class BaseConfig(ABC):
|
|||
|
||||
def add_tools_to_optional_params(
|
||||
self,
|
||||
optional_params: dict[str, object], # mutable-ok: mirrors override contract
|
||||
optional_params: dict[str, object],
|
||||
tools: list[ChatCompletionToolParam], # mutable-ok: mirrors override contract
|
||||
) -> dict[str, object]: # mutable-ok: mirrors override contract
|
||||
) -> dict[str, object]:
|
||||
return self._add_tools_to_optional_params(optional_params, tools)
|
||||
|
||||
def translate_developer_role_to_system_role(
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ def _responses_request_keys() -> frozenset[str]:
|
|||
def responses_batch_body_to_chat_body(
|
||||
openai_request_body: Mapping[str, object],
|
||||
custom_llm_provider: str | None = None,
|
||||
) -> dict[str, object]: # mutable-ok: provider transforms take the bridged chat body as a plain dict
|
||||
) -> dict[str, object]:
|
||||
"""
|
||||
Rewrite the body of an OpenAI `/v1/responses` batch record as a Chat Completions body.
|
||||
|
||||
|
|
|
|||
|
|
@ -166,7 +166,7 @@ class BaseFilesConfig(BaseConfig):
|
|||
self,
|
||||
raw_response: httpx.Response,
|
||||
optional_params: Mapping[str, object],
|
||||
litellm_params: dict, # mutable-ok: carries provider stashes from the request transform to the response one
|
||||
litellm_params: dict,
|
||||
) -> tuple[str, dict[str, str]] | None:
|
||||
"""Request for the page after `raw_response`, or None once the listing is complete."""
|
||||
return None
|
||||
|
|
|
|||
|
|
@ -121,7 +121,7 @@ class BaseTranslation(ABC):
|
|||
|
||||
@staticmethod
|
||||
def merge_user_api_key_metadata_into_request(
|
||||
request_data: dict[str, Any], # mutable-ok: proxy hooks share and mutate the request payload dict in place
|
||||
request_data: dict[str, Any],
|
||||
user_api_key_dict: Optional["UserAPIKeyAuth"],
|
||||
) -> None:
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ StreamStateT = TypeVar("StreamStateT")
|
|||
|
||||
def event_list(*events: Event) -> Sequence[Event]:
|
||||
"""A transform_stream_line result. One place builds it so every parser returns the same shape."""
|
||||
return list(events) # mutable-ok: stream-line results are list-shaped; callers and tests compare with list literals
|
||||
return list(events)
|
||||
|
||||
|
||||
class HarnessTurnError(HarnessError):
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ _JSON_OBJECT_ADAPTER: Final = TypeAdapter(dict[str, object])
|
|||
_RAW_DECODE_ADAPTER: Final = TypeAdapter(tuple[object, int])
|
||||
|
||||
|
||||
def gateway_headers(ctx: SessionContext) -> dict[str, str]: # mutable-ok: acompletion(extra_headers=) requires dict
|
||||
def gateway_headers(ctx: SessionContext) -> dict[str, str]:
|
||||
metadata_json: Final = json.dumps(dict(ctx.metadata), default=str) if ctx.metadata else None
|
||||
return {
|
||||
"x-litellm-tags": f"harness,{ctx.harness.value}",
|
||||
|
|
@ -42,7 +42,7 @@ def normalize_tool_name(native_name: str, mapping: Mapping[str, str]) -> str:
|
|||
def native_tool_names(normalized: Sequence[str], mapping: Mapping[str, Sequence[str]]) -> Sequence[str]:
|
||||
"""Native names for normalized tool names, de-duplicated, order kept."""
|
||||
expanded: Final = itertools.chain.from_iterable(mapping.get(name, (name,)) for name in normalized)
|
||||
return list(dict.fromkeys(expanded)) # mutable-ok: public helper whose callers/tests compare against list literals
|
||||
return list(dict.fromkeys(expanded))
|
||||
|
||||
|
||||
def last_json_object(text: str) -> str | None:
|
||||
|
|
@ -80,22 +80,22 @@ def strict_json_schema(schema: JSONValue, depth: int = 0) -> JSONValue:
|
|||
if depth > DEFAULT_MAX_RECURSE_DEPTH:
|
||||
raise ValueError(f"output schema is nested deeper than {DEFAULT_MAX_RECURSE_DEPTH} levels")
|
||||
if isinstance(schema, list):
|
||||
return [strict_json_schema(entry, depth + 1) for entry in schema] # mutable-ok: JSON document output
|
||||
return [strict_json_schema(entry, depth + 1) for entry in schema]
|
||||
if not isinstance(schema, dict):
|
||||
return schema
|
||||
entries: Final = ((key, strict_json_schema(value, depth + 1)) for key, value in schema.items())
|
||||
result = dict(entries) # mutable-ok: JSON document; "default" is popped below
|
||||
result = dict(entries)
|
||||
if "$ref" in result:
|
||||
return {"$ref": result["$ref"]} # mutable-ok: JSONValue output is a plain JSON document
|
||||
return {"$ref": result["$ref"]}
|
||||
result.pop("default", None)
|
||||
properties = result.get("properties")
|
||||
if result.get("type") == "object" or isinstance(properties, dict):
|
||||
props = properties if isinstance(properties, dict) else {} # mutable-ok: JSONValue object member
|
||||
props = properties if isinstance(properties, dict) else {}
|
||||
required: Final[list[JSONValue]] = list(props) # mutable-ok: JSON array in the output schema
|
||||
strict: Final[Mapping[str, JSONValue]] = MappingProxyType(
|
||||
{"properties": props, "required": required, "additionalProperties": False}
|
||||
)
|
||||
result = {**result, **strict} # mutable-ok: JSON document output
|
||||
result = {**result, **strict}
|
||||
return result
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -92,11 +92,11 @@ class OCRResponse(LiteLLMPydanticObjectBase):
|
|||
_hidden_params: dict = PrivateAttr(default_factory=dict)
|
||||
|
||||
@property
|
||||
def hidden_params(self) -> dict[str, builtins.object]: # mutable-ok: API requires mutation
|
||||
def hidden_params(self) -> dict[str, builtins.object]:
|
||||
return self._hidden_params
|
||||
|
||||
@hidden_params.setter
|
||||
def hidden_params(self, hidden_params: dict[str, builtins.object]) -> None: # mutable-ok: API requires mutation
|
||||
def hidden_params(self, hidden_params: dict[str, builtins.object]) -> None:
|
||||
self._hidden_params = hidden_params
|
||||
|
||||
def set_provider_native_response(self, native_response: Mapping[str, builtins.object]) -> None:
|
||||
|
|
|
|||
|
|
@ -29,11 +29,11 @@ class ContainerHandle(LiteLLMPydanticObjectBase):
|
|||
_hidden_params: dict = PrivateAttr(default_factory=dict)
|
||||
|
||||
@property
|
||||
def hidden_params(self) -> dict[str, builtins.object]: # mutable-ok: API requires mutation
|
||||
def hidden_params(self) -> dict[str, builtins.object]:
|
||||
return self._hidden_params
|
||||
|
||||
@hidden_params.setter
|
||||
def hidden_params(self, hidden_params: dict[str, builtins.object]) -> None: # mutable-ok: API requires mutation
|
||||
def hidden_params(self, hidden_params: dict[str, builtins.object]) -> None:
|
||||
self._hidden_params = hidden_params
|
||||
|
||||
|
||||
|
|
@ -52,11 +52,11 @@ class CodeExecutionResult(LiteLLMPydanticObjectBase):
|
|||
_hidden_params: dict = PrivateAttr(default_factory=dict)
|
||||
|
||||
@property
|
||||
def hidden_params(self) -> dict[str, builtins.object]: # mutable-ok: API requires mutation
|
||||
def hidden_params(self) -> dict[str, builtins.object]:
|
||||
return self._hidden_params
|
||||
|
||||
@hidden_params.setter
|
||||
def hidden_params(self, hidden_params: dict[str, builtins.object]) -> None: # mutable-ok: API requires mutation
|
||||
def hidden_params(self, hidden_params: dict[str, builtins.object]) -> None:
|
||||
self._hidden_params = hidden_params
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -79,11 +79,11 @@ class SearchResponse(LiteLLMPydanticObjectBase):
|
|||
_hidden_params: dict = PrivateAttr(default_factory=dict)
|
||||
|
||||
@property
|
||||
def hidden_params(self) -> dict[str, builtins.object]: # mutable-ok: API requires mutation
|
||||
def hidden_params(self) -> dict[str, builtins.object]:
|
||||
return self._hidden_params
|
||||
|
||||
@hidden_params.setter
|
||||
def hidden_params(self, hidden_params: dict[str, builtins.object]) -> None: # mutable-ok: API requires mutation
|
||||
def hidden_params(self, hidden_params: dict[str, builtins.object]) -> None:
|
||||
self._hidden_params = hidden_params
|
||||
|
||||
|
||||
|
|
@ -206,12 +206,12 @@ class BaseSearchConfig:
|
|||
|
||||
def sign_request(
|
||||
self,
|
||||
headers: dict[str, str], # mutable-ok: matches the request header dict every other hook on this base takes
|
||||
optional_params: dict[str, object], # mutable-ok: matches every other hook on this base
|
||||
headers: dict[str, str],
|
||||
optional_params: dict[str, object],
|
||||
request_data: dict[str, object] | list[dict[str, object]], # mutable-ok: transform_search_request's body
|
||||
api_base: str,
|
||||
api_key: str | None = None,
|
||||
) -> tuple[dict[str, str], bytes | None]: # mutable-ok: the handler passes these headers straight to httpx
|
||||
) -> tuple[dict[str, str], bytes | None]:
|
||||
"""
|
||||
OPTIONAL
|
||||
|
||||
|
|
|
|||
|
|
@ -170,7 +170,7 @@ def build_web_identity_session_policy() -> WebIdentitySessionPolicy:
|
|||
|
||||
|
||||
def pop_aws_auth_params(
|
||||
optional_params: MutableMapping[str, object], # mutable-ok: pops the aws_* keys out of the caller's mapping
|
||||
optional_params: MutableMapping[str, object],
|
||||
) -> AwsAuthParams:
|
||||
return AwsAuthParams.model_validate(
|
||||
MappingProxyType({key: optional_params.pop(key, None) for key in AWS_AUTH_PARAM_KEYS})
|
||||
|
|
@ -792,7 +792,7 @@ class BaseAWSLLM(SignsRequestsWithAWS):
|
|||
|
||||
def get_aws_region_name(
|
||||
self,
|
||||
optional_params: dict[str, object], # mutable-ok: mirrors override contract
|
||||
optional_params: dict[str, object],
|
||||
model: str | None = None,
|
||||
model_id: str | None = None,
|
||||
) -> str:
|
||||
|
|
@ -1535,7 +1535,7 @@ class BaseAWSLLM(SignsRequestsWithAWS):
|
|||
@overload
|
||||
def _get_boto_credentials_from_optional_params(
|
||||
self,
|
||||
optional_params: dict, # mutable-ok: the implementation pops the aws_* keys out of the caller's dict in place
|
||||
optional_params: dict,
|
||||
model: str | None = None,
|
||||
bearer_token: None = None,
|
||||
) -> Boto3CredentialsInfo: ...
|
||||
|
|
@ -1543,7 +1543,7 @@ class BaseAWSLLM(SignsRequestsWithAWS):
|
|||
@overload
|
||||
def _get_boto_credentials_from_optional_params(
|
||||
self,
|
||||
optional_params: dict, # mutable-ok: the implementation pops the aws_* keys out of the caller's dict in place
|
||||
optional_params: dict,
|
||||
model: str | None = None,
|
||||
*,
|
||||
bearer_token: str,
|
||||
|
|
|
|||
|
|
@ -195,7 +195,7 @@ class AmazonAgentCoreConfig(BaseConfig, BaseAWSLLM):
|
|||
|
||||
def get_runtime_session_id(
|
||||
self,
|
||||
optional_params: dict[str, object], # mutable-ok: mirrors override contract
|
||||
optional_params: dict[str, object],
|
||||
) -> str:
|
||||
return self._get_runtime_session_id(optional_params)
|
||||
|
||||
|
|
@ -210,7 +210,7 @@ class AmazonAgentCoreConfig(BaseConfig, BaseAWSLLM):
|
|||
|
||||
def get_runtime_user_id(
|
||||
self,
|
||||
optional_params: dict[str, object], # mutable-ok: mirrors override contract
|
||||
optional_params: dict[str, object],
|
||||
) -> str | None:
|
||||
return self._get_runtime_user_id(optional_params)
|
||||
|
||||
|
|
|
|||
|
|
@ -224,7 +224,7 @@ class BedrockRuntimeChatCompletionsStreamingHandler(OpenAIChatCompletionStreamin
|
|||
super().__init__(streaming_response=streaming_response, sync_stream=sync_stream, json_mode=json_mode)
|
||||
self._splitters: Mapping[int, ReasoningTagSplitter] = MappingProxyType({})
|
||||
|
||||
def chunk_parser(self, chunk: dict) -> ModelResponseStream: # mutable-ok: BaseModelResponseIterator signature
|
||||
def chunk_parser(self, chunk: dict) -> ModelResponseStream:
|
||||
parsed: Final = super().chunk_parser(chunk)
|
||||
for choice in parsed.choices:
|
||||
next_state, reasoning, content = _split_streamed_content(
|
||||
|
|
@ -275,20 +275,20 @@ class AmazonBedrockRuntimeChatCompletionsConfig(OpenAILikeChatConfig):
|
|||
self,
|
||||
error_message: str,
|
||||
status_code: int,
|
||||
headers: dict[str, object] | httpx.Headers, # mutable-ok: BaseConfig signature
|
||||
headers: dict[str, object] | httpx.Headers,
|
||||
) -> BaseLLMException:
|
||||
return BedrockError(status_code=status_code, message=error_message, headers=headers)
|
||||
|
||||
def validate_environment(
|
||||
self,
|
||||
headers: dict, # mutable-ok: BaseConfig signature
|
||||
headers: dict,
|
||||
model: str,
|
||||
messages: list[AllMessageValues],
|
||||
optional_params: dict, # mutable-ok: BaseConfig signature
|
||||
litellm_params: dict, # mutable-ok: BaseConfig signature
|
||||
optional_params: dict,
|
||||
litellm_params: dict,
|
||||
api_key: str | None = None,
|
||||
api_base: str | None = None,
|
||||
) -> dict: # mutable-ok: BaseConfig signature
|
||||
) -> dict:
|
||||
return super().validate_environment(
|
||||
headers=headers,
|
||||
model=model,
|
||||
|
|
@ -304,8 +304,8 @@ class AmazonBedrockRuntimeChatCompletionsConfig(OpenAILikeChatConfig):
|
|||
api_base: str | None,
|
||||
api_key: str | None,
|
||||
model: str,
|
||||
optional_params: dict, # mutable-ok: BaseConfig signature
|
||||
litellm_params: dict, # mutable-ok: BaseConfig signature
|
||||
optional_params: dict,
|
||||
litellm_params: dict,
|
||||
stream: bool | None = None,
|
||||
) -> str:
|
||||
if api_base is not None and "chat/completions" in api_base:
|
||||
|
|
@ -328,9 +328,7 @@ class AmazonBedrockRuntimeChatCompletionsConfig(OpenAILikeChatConfig):
|
|||
return f"{base}/chat/completions"
|
||||
return f"{base}/openai/v1/chat/completions"
|
||||
|
||||
def _params_with_region_from_path(
|
||||
self, optional_params: dict, model: str | None
|
||||
) -> dict: # mutable-ok: BaseAWSLLM's region resolver and signer take a plain dict
|
||||
def _params_with_region_from_path(self, optional_params: dict, model: str | None) -> dict:
|
||||
region_from_path, _ = split_bedrock_region_path(model or "")
|
||||
if region_from_path is None or optional_params.get("aws_region_name") is not None:
|
||||
return optional_params
|
||||
|
|
@ -338,15 +336,15 @@ class AmazonBedrockRuntimeChatCompletionsConfig(OpenAILikeChatConfig):
|
|||
|
||||
def sign_request(
|
||||
self,
|
||||
headers: dict, # mutable-ok: BaseConfig signature
|
||||
optional_params: dict, # mutable-ok: BaseConfig signature
|
||||
request_data: dict, # mutable-ok: BaseConfig signature
|
||||
headers: dict,
|
||||
optional_params: dict,
|
||||
request_data: dict,
|
||||
api_base: str,
|
||||
api_key: str | None = None,
|
||||
model: str | None = None,
|
||||
stream: bool | None = None,
|
||||
fake_stream: bool | None = None,
|
||||
) -> tuple[dict, bytes | None]: # mutable-ok: BaseConfig signature
|
||||
) -> tuple[dict, bytes | None]:
|
||||
return self._aws_signer._sign_request( # pyright: ignore[reportPrivateUsage] # BaseAWSLLM has no public signer
|
||||
service_name="bedrock",
|
||||
headers=headers,
|
||||
|
|
@ -361,12 +359,12 @@ class AmazonBedrockRuntimeChatCompletionsConfig(OpenAILikeChatConfig):
|
|||
|
||||
def map_openai_params(
|
||||
self,
|
||||
non_default_params: dict, # mutable-ok: BaseConfig signature
|
||||
optional_params: dict, # mutable-ok: BaseConfig signature
|
||||
non_default_params: dict,
|
||||
optional_params: dict,
|
||||
model: str,
|
||||
drop_params: bool,
|
||||
replace_max_completion_tokens_with_max_tokens: bool = False,
|
||||
) -> dict: # mutable-ok: BaseConfig signature
|
||||
) -> dict:
|
||||
mapped: Final = _PARAMS_DICT_ADAPTER.validate_python(
|
||||
super().map_openai_params(
|
||||
non_default_params=non_default_params,
|
||||
|
|
@ -404,9 +402,7 @@ class AmazonBedrockRuntimeChatCompletionsConfig(OpenAILikeChatConfig):
|
|||
)
|
||||
)
|
||||
|
||||
def _inference_params(
|
||||
self, optional_params: Mapping[str, object]
|
||||
) -> dict[str, object]: # mutable-ok: BaseConfig signature of transform_request
|
||||
def _inference_params(self, optional_params: Mapping[str, object]) -> dict[str, object]:
|
||||
return {
|
||||
key: value
|
||||
for key, value in optional_params.items()
|
||||
|
|
@ -417,10 +413,10 @@ class AmazonBedrockRuntimeChatCompletionsConfig(OpenAILikeChatConfig):
|
|||
self,
|
||||
model: str,
|
||||
messages: list[AllMessageValues], # mutable-ok: BaseConfig signature
|
||||
optional_params: dict, # mutable-ok: BaseConfig signature
|
||||
litellm_params: dict, # mutable-ok: BaseConfig signature
|
||||
headers: dict, # mutable-ok: BaseConfig signature
|
||||
) -> dict: # mutable-ok: BaseConfig signature
|
||||
optional_params: dict,
|
||||
litellm_params: dict,
|
||||
headers: dict,
|
||||
) -> dict:
|
||||
optional_params_view: Final = _PARAMS_DICT_ADAPTER.validate_python(optional_params)
|
||||
return super().transform_request(
|
||||
model=split_bedrock_region_path(model)[1],
|
||||
|
|
@ -434,10 +430,10 @@ class AmazonBedrockRuntimeChatCompletionsConfig(OpenAILikeChatConfig):
|
|||
self,
|
||||
model: str,
|
||||
messages: list[AllMessageValues], # mutable-ok: BaseConfig signature
|
||||
optional_params: dict, # mutable-ok: BaseConfig signature
|
||||
litellm_params: dict, # mutable-ok: BaseConfig signature
|
||||
headers: dict, # mutable-ok: BaseConfig signature
|
||||
) -> dict: # mutable-ok: BaseConfig signature
|
||||
optional_params: dict,
|
||||
litellm_params: dict,
|
||||
headers: dict,
|
||||
) -> dict:
|
||||
optional_params_view: Final = _PARAMS_DICT_ADAPTER.validate_python(optional_params)
|
||||
return await super().async_transform_request(
|
||||
model=split_bedrock_region_path(model)[1],
|
||||
|
|
@ -453,10 +449,10 @@ class AmazonBedrockRuntimeChatCompletionsConfig(OpenAILikeChatConfig):
|
|||
raw_response: httpx.Response,
|
||||
model_response: ModelResponse,
|
||||
logging_obj: "LiteLLMLoggingObj",
|
||||
request_data: dict, # mutable-ok: BaseConfig signature
|
||||
request_data: dict,
|
||||
messages: list[AllMessageValues], # mutable-ok: BaseConfig signature
|
||||
optional_params: dict, # mutable-ok: BaseConfig signature
|
||||
litellm_params: dict, # mutable-ok: BaseConfig signature
|
||||
optional_params: dict,
|
||||
litellm_params: dict,
|
||||
encoding: "tiktoken.Encoding | None",
|
||||
api_key: str | None = None,
|
||||
json_mode: bool | None = None,
|
||||
|
|
|
|||
|
|
@ -779,8 +779,8 @@ class AWSEventStreamDecoder:
|
|||
|
||||
def chunk_parser(
|
||||
self,
|
||||
chunk_data: dict[str, object], # mutable-ok: mirrors override contract
|
||||
) -> GChunk | ModelResponseStream | dict[str, object]: # mutable-ok: mirrors override contract
|
||||
chunk_data: dict[str, object],
|
||||
) -> GChunk | ModelResponseStream | dict[str, object]:
|
||||
return self._chunk_parser(chunk_data)
|
||||
|
||||
def iter_bytes(
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ class BedrockClaudePlatformMixin(BaseAWSLLM):
|
|||
self,
|
||||
error_message: str,
|
||||
status_code: int,
|
||||
headers: dict[str, object] | httpx.Headers, # mutable-ok: base passes response headers as a dict
|
||||
headers: dict[str, object] | httpx.Headers,
|
||||
) -> BedrockError:
|
||||
return BedrockError(status_code=status_code, message=error_message, headers=headers)
|
||||
|
||||
|
|
|
|||
|
|
@ -253,7 +253,7 @@ def _bedrock_model_supports(model: str, key: str) -> bool:
|
|||
|
||||
def apply_bedrock_invoke_structured_output(
|
||||
model: str,
|
||||
request_body: dict[str, object], # mutable-ok: edited in place like siblings
|
||||
request_body: dict[str, object],
|
||||
) -> None:
|
||||
"""
|
||||
Route Anthropic structured-output params to what the Bedrock model supports.
|
||||
|
|
@ -295,7 +295,7 @@ def apply_bedrock_invoke_structured_output(
|
|||
|
||||
def strip_unsupported_bedrock_invoke_output_config_keys(
|
||||
model: str,
|
||||
request_body: dict[str, object], # mutable-ok: edited in place like siblings
|
||||
request_body: dict[str, object],
|
||||
) -> None:
|
||||
"""
|
||||
Drop ``output_config`` keys the Bedrock model does not accept.
|
||||
|
|
|
|||
|
|
@ -207,11 +207,11 @@ class AmazonNovaEmbeddingConfig:
|
|||
def transform_request(
|
||||
self,
|
||||
input: str,
|
||||
inference_params: dict[str, object], # mutable-ok: mirrors override contract
|
||||
inference_params: dict[str, object],
|
||||
async_invoke_route: bool = False,
|
||||
model_id: str | None = None,
|
||||
output_s3_uri: str | None = None,
|
||||
) -> dict[str, object]: # mutable-ok: mirrors override contract
|
||||
) -> dict[str, object]:
|
||||
return self._transform_request(input, inference_params, async_invoke_route, model_id, output_s3_uri)
|
||||
|
||||
def _wrap_async_invoke_request(
|
||||
|
|
@ -372,7 +372,7 @@ class AmazonNovaEmbeddingConfig:
|
|||
|
||||
def transform_async_invoke_response(
|
||||
self,
|
||||
response: dict[str, object], # mutable-ok: mirrors override contract
|
||||
response: dict[str, object],
|
||||
model: str,
|
||||
) -> EmbeddingResponse:
|
||||
return self._transform_async_invoke_response(response, model)
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ class AmazonTitanG1Config:
|
|||
def transform_request(
|
||||
self,
|
||||
input: str,
|
||||
inference_params: dict[str, object], # mutable-ok: mirrors override contract
|
||||
inference_params: dict[str, object],
|
||||
) -> AmazonTitanG1EmbeddingRequest:
|
||||
return self._transform_request(input, inference_params)
|
||||
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ class AmazonTitanMultimodalEmbeddingG1Config:
|
|||
def transform_request(
|
||||
self,
|
||||
input: str,
|
||||
inference_params: dict[str, object], # mutable-ok: mirrors override contract
|
||||
inference_params: dict[str, object],
|
||||
) -> AmazonTitanMultimodalEmbeddingRequest:
|
||||
return self._transform_request(input, inference_params)
|
||||
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ class AmazonTitanV2Config:
|
|||
def transform_request(
|
||||
self,
|
||||
input: str,
|
||||
inference_params: dict[str, object], # mutable-ok: mirrors override contract
|
||||
inference_params: dict[str, object],
|
||||
) -> AmazonTitanV2EmbeddingRequest:
|
||||
return self._transform_request(input, inference_params)
|
||||
|
||||
|
|
|
|||
|
|
@ -46,6 +46,6 @@ class BedrockCohereEmbeddingConfig:
|
|||
self,
|
||||
model: str,
|
||||
input: list[str], # mutable-ok: mirrors override contract
|
||||
inference_params: dict[str, object], # mutable-ok: mirrors override contract
|
||||
inference_params: dict[str, object],
|
||||
) -> CohereEmbeddingRequest:
|
||||
return self._transform_request(model, input, inference_params)
|
||||
|
|
|
|||
|
|
@ -67,14 +67,14 @@ class BedrockEmbedding(BaseAWSLLM):
|
|||
@overload
|
||||
def _load_credentials(
|
||||
self,
|
||||
optional_params: dict, # mutable-ok: the implementation pops the aws_* keys out of the caller's dict in place
|
||||
optional_params: dict,
|
||||
bearer_token: None = None,
|
||||
) -> tuple[Credentials, str]: ...
|
||||
|
||||
@overload
|
||||
def _load_credentials(
|
||||
self,
|
||||
optional_params: dict, # mutable-ok: the implementation pops the aws_* keys out of the caller's dict in place
|
||||
optional_params: dict,
|
||||
bearer_token: str,
|
||||
) -> tuple[None, str]: ...
|
||||
|
||||
|
|
|
|||
|
|
@ -275,7 +275,7 @@ class TwelveLabsMarengoEmbeddingConfig:
|
|||
def transform_request(
|
||||
self,
|
||||
input: str,
|
||||
inference_params: dict[str, object], # mutable-ok: mirrors override contract
|
||||
inference_params: dict[str, object],
|
||||
async_invoke_route: bool = False,
|
||||
model_id: str | None = None,
|
||||
output_s3_uri: str | None = None,
|
||||
|
|
@ -390,7 +390,7 @@ class TwelveLabsMarengoEmbeddingConfig:
|
|||
|
||||
def transform_async_invoke_response(
|
||||
self,
|
||||
response: dict[str, object], # mutable-ok: mirrors override contract
|
||||
response: dict[str, object],
|
||||
model: str,
|
||||
) -> EmbeddingResponse:
|
||||
return self._transform_async_invoke_response(response, model)
|
||||
|
|
|
|||
|
|
@ -1356,9 +1356,7 @@ class BedrockFilesConfig(BaseAWSLLM, BaseFilesConfig):
|
|||
url: Final = f"{target.endpoint_url}/{bucket_name}/"
|
||||
listing_query: Final = _listing_query(configured_prefix, purpose)
|
||||
continuation_query: Final = (("continuation-token", continuation_token),) if continuation_token else ()
|
||||
query: Final[dict[str, str]] = dict( # mutable-ok: the base files contract returns the query as a dict
|
||||
listing_query + continuation_query
|
||||
)
|
||||
query: Final[dict[str, str]] = dict(listing_query + continuation_query)
|
||||
signed_headers: Final = self._sign_s3_request_without_body(
|
||||
method="GET",
|
||||
api_base=f"{url}?{urlencode(query, quote_via=quote, safe='')}",
|
||||
|
|
|
|||
|
|
@ -240,7 +240,7 @@ class BedrockAmazonNovaCanvasImageEditConfig(BaseImageEditConfig):
|
|||
self,
|
||||
error_message: str,
|
||||
status_code: int,
|
||||
headers: dict[str, object] | httpx.Headers, # mutable-ok: base passes response headers as a dict
|
||||
headers: dict[str, object] | httpx.Headers,
|
||||
) -> BedrockError:
|
||||
return BedrockError(status_code=status_code, message=error_message, headers=headers)
|
||||
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ class BedrockStabilityImageEditConfig(BaseImageEditConfig):
|
|||
self,
|
||||
error_message: str,
|
||||
status_code: int,
|
||||
headers: dict[str, object] | httpx.Headers, # mutable-ok: base passes response headers as a dict
|
||||
headers: dict[str, object] | httpx.Headers,
|
||||
) -> BedrockError:
|
||||
return BedrockError(status_code=status_code, message=error_message, headers=headers)
|
||||
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ class AmazonAnthropicClaudeMessagesConfig(
|
|||
self,
|
||||
error_message: str,
|
||||
status_code: int,
|
||||
headers: dict[str, object] | httpx.Headers, # mutable-ok: base passes response headers as a dict
|
||||
headers: dict[str, object] | httpx.Headers,
|
||||
) -> BedrockError:
|
||||
return BedrockError(status_code=status_code, message=error_message, headers=headers)
|
||||
|
||||
|
|
|
|||
|
|
@ -129,7 +129,7 @@ class BedrockPassthroughConfig(BaseAWSLLM, BedrockModelInfo, BedrockEventStreamD
|
|||
self,
|
||||
error_message: str,
|
||||
status_code: int,
|
||||
headers: dict[str, object] | httpx.Headers, # mutable-ok: base passes response headers as a dict
|
||||
headers: dict[str, object] | httpx.Headers,
|
||||
) -> BedrockError:
|
||||
return BedrockError(status_code=status_code, message=error_message, headers=headers)
|
||||
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ def _should_log_event(openai_message: Mapping[str, object]) -> bool:
|
|||
class RealtimeClientWebSocket(Protocol):
|
||||
"""The client-facing websocket surface the realtime bridge talks to."""
|
||||
|
||||
scope: MutableMapping[str, object] # mutable-ok: the ASGI scope is the per-connection state store
|
||||
scope: MutableMapping[str, object]
|
||||
|
||||
async def receive_text(self) -> str: ...
|
||||
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ class BedrockRealtimeConfig(BaseRealtimeConfig):
|
|||
self,
|
||||
error_message: str,
|
||||
status_code: int,
|
||||
headers: dict[str, object] | httpx.Headers, # mutable-ok: base passes response headers as a dict
|
||||
headers: dict[str, object] | httpx.Headers,
|
||||
) -> BedrockError:
|
||||
return BedrockError(status_code=status_code, message=error_message, headers=headers)
|
||||
|
||||
|
|
|
|||
|
|
@ -117,6 +117,6 @@ class BedrockRerankConfig:
|
|||
|
||||
def transform_response(
|
||||
self,
|
||||
response: dict[str, object], # mutable-ok: mirrors override contract
|
||||
response: dict[str, object],
|
||||
) -> RerankResponse:
|
||||
return self._transform_response(response)
|
||||
|
|
|
|||
|
|
@ -157,7 +157,7 @@ def inline_remote_image_urls(
|
|||
|
||||
def _without_disabled_reasoning_effort(
|
||||
params: Mapping[str, object], model: str, drop_params: bool
|
||||
) -> dict[str, object]: # mutable-ok: becomes the map_openai_params return value
|
||||
) -> dict[str, object]:
|
||||
reasoning: Final = params.get("reasoning")
|
||||
effort: Final = reasoning.get("effort") if isinstance(reasoning, Mapping) else None
|
||||
if not isinstance(reasoning, Mapping) or not isinstance(effort, str):
|
||||
|
|
@ -220,7 +220,7 @@ class BedrockOpenAIResponsesConfig(BaseAWSLLM, OpenAIResponsesAPIConfig):
|
|||
def get_complete_url(
|
||||
self,
|
||||
api_base: str | None,
|
||||
litellm_params: dict, # mutable-ok: signature fixed by the BaseResponsesAPIConfig override contract
|
||||
litellm_params: dict,
|
||||
) -> str:
|
||||
region: Final = self._get_aws_region_name(optional_params=litellm_params, model=None)
|
||||
override: Final = (
|
||||
|
|
@ -244,10 +244,10 @@ class BedrockOpenAIResponsesConfig(BaseAWSLLM, OpenAIResponsesAPIConfig):
|
|||
|
||||
def validate_environment(
|
||||
self,
|
||||
headers: dict, # mutable-ok: signature fixed by the BaseResponsesAPIConfig override contract
|
||||
headers: dict,
|
||||
model: str,
|
||||
litellm_params: GenericLiteLLMParams | None,
|
||||
) -> dict: # mutable-ok: signature fixed by the BaseResponsesAPIConfig override contract
|
||||
) -> dict:
|
||||
api_key: Final = litellm_params.api_key if litellm_params is not None else None
|
||||
bearer: Final = resolve_bedrock_bearer_token(api_key)
|
||||
if not bearer:
|
||||
|
|
@ -256,15 +256,15 @@ class BedrockOpenAIResponsesConfig(BaseAWSLLM, OpenAIResponsesAPIConfig):
|
|||
|
||||
def sign_request(
|
||||
self,
|
||||
headers: dict, # mutable-ok: signature fixed by the BaseResponsesAPIConfig override contract
|
||||
optional_params: dict, # mutable-ok: same
|
||||
request_data: dict, # mutable-ok: same
|
||||
headers: dict,
|
||||
optional_params: dict,
|
||||
request_data: dict,
|
||||
api_base: str,
|
||||
api_key: str | None = None,
|
||||
model: str | None = None,
|
||||
stream: bool | None = None,
|
||||
fake_stream: bool | None = None,
|
||||
) -> "tuple[dict, bytes | None]": # mutable-ok: signature fixed by the override contract
|
||||
) -> "tuple[dict, bytes | None]":
|
||||
if resolve_bedrock_bearer_token(api_key):
|
||||
# Bedrock API keys are Bearer credentials; SigV4 on top would be wrong.
|
||||
return headers, None
|
||||
|
|
@ -284,7 +284,7 @@ class BedrockOpenAIResponsesConfig(BaseAWSLLM, OpenAIResponsesAPIConfig):
|
|||
response_api_optional_params: ResponsesAPIOptionalRequestParams,
|
||||
model: str,
|
||||
drop_params: bool,
|
||||
) -> dict: # mutable-ok: signature fixed by the override contract
|
||||
) -> dict:
|
||||
mapped: Final = super().map_openai_params(
|
||||
response_api_optional_params=response_api_optional_params, model=model, drop_params=drop_params
|
||||
)
|
||||
|
|
@ -316,10 +316,10 @@ class BedrockOpenAIResponsesConfig(BaseAWSLLM, OpenAIResponsesAPIConfig):
|
|||
self,
|
||||
model: str,
|
||||
input: "str | ResponseInputParam",
|
||||
response_api_optional_request_params: dict, # mutable-ok: signature fixed by the override contract
|
||||
response_api_optional_request_params: dict,
|
||||
litellm_params: GenericLiteLLMParams,
|
||||
headers: dict, # mutable-ok: same
|
||||
) -> dict: # mutable-ok: same
|
||||
headers: dict,
|
||||
) -> dict:
|
||||
inlined: Final = MappingProxyType({url: self.fetch_image(url) for url in collect_remote_image_urls(input)})
|
||||
return self._transform_inlined_request(
|
||||
model=model,
|
||||
|
|
@ -333,10 +333,10 @@ class BedrockOpenAIResponsesConfig(BaseAWSLLM, OpenAIResponsesAPIConfig):
|
|||
self,
|
||||
model: str,
|
||||
input: "str | ResponseInputParam",
|
||||
response_api_optional_request_params: dict, # mutable-ok: signature fixed by the override contract
|
||||
response_api_optional_request_params: dict,
|
||||
litellm_params: GenericLiteLLMParams,
|
||||
headers: dict, # mutable-ok: same
|
||||
) -> dict: # mutable-ok: same
|
||||
headers: dict,
|
||||
) -> dict:
|
||||
remote_urls: Final = collect_remote_image_urls(input)
|
||||
data_uris: Final = await asyncio.gather(*(self.async_fetch_image(url) for url in remote_urls))
|
||||
return self._transform_inlined_request(
|
||||
|
|
@ -351,10 +351,10 @@ class BedrockOpenAIResponsesConfig(BaseAWSLLM, OpenAIResponsesAPIConfig):
|
|||
self,
|
||||
model: str,
|
||||
input: "str | ResponseInputParam",
|
||||
response_api_optional_request_params: dict, # mutable-ok: signature fixed by the override contract
|
||||
response_api_optional_request_params: dict,
|
||||
litellm_params: GenericLiteLLMParams,
|
||||
headers: dict, # mutable-ok: same
|
||||
) -> dict: # mutable-ok: same
|
||||
headers: dict,
|
||||
) -> dict:
|
||||
normalized_input, rewritten_types = normalize_codex_input_items(input)
|
||||
if rewritten_types:
|
||||
verbose_logger.warning(
|
||||
|
|
|
|||
|
|
@ -168,11 +168,11 @@ class AgentCoreSearchConfig(BaseSearchConfig, BaseAWSLLM):
|
|||
|
||||
def validate_environment(
|
||||
self,
|
||||
headers: dict, # mutable-ok: BaseSearchConfig hands providers the mutable request header dict
|
||||
headers: dict,
|
||||
api_key: str | None = None,
|
||||
api_base: str | None = None,
|
||||
**kwargs: object, # kwargs-ok: BaseSearchConfig.validate_environment forwards provider-specific extras
|
||||
) -> dict: # mutable-ok: the handler passes these headers straight to httpx, which wants a dict
|
||||
) -> dict:
|
||||
"""
|
||||
Set MCP transport headers. Per the MCP Streamable HTTP transport spec,
|
||||
the client MUST accept both application/json and text/event-stream, and
|
||||
|
|
@ -192,7 +192,7 @@ class AgentCoreSearchConfig(BaseSearchConfig, BaseAWSLLM):
|
|||
def get_complete_url(
|
||||
self,
|
||||
api_base: str | None,
|
||||
optional_params: dict, # mutable-ok: BaseSearchConfig passes optional params as a dict
|
||||
optional_params: dict,
|
||||
data: dict | list[dict] | None = None, # mutable-ok: BaseSearchConfig request bodies are JSON dicts
|
||||
**kwargs: object, # kwargs-ok: BaseSearchConfig.get_complete_url forwards provider-specific extras
|
||||
) -> str:
|
||||
|
|
@ -208,9 +208,9 @@ class AgentCoreSearchConfig(BaseSearchConfig, BaseAWSLLM):
|
|||
def transform_search_request(
|
||||
self,
|
||||
query: str | list[str], # mutable-ok: BaseSearchConfig accepts a list of queries
|
||||
optional_params: dict, # mutable-ok: BaseSearchConfig passes optional params as a dict
|
||||
optional_params: dict,
|
||||
**kwargs: object, # kwargs-ok: BaseSearchConfig.transform_search_request forwards provider-specific extras
|
||||
) -> dict: # mutable-ok: the JSON-RPC body is serialized as a JSON object
|
||||
) -> dict:
|
||||
"""
|
||||
Transform Search request to an MCP tools/call request.
|
||||
|
||||
|
|
@ -252,12 +252,12 @@ class AgentCoreSearchConfig(BaseSearchConfig, BaseAWSLLM):
|
|||
|
||||
def sign_request(
|
||||
self,
|
||||
headers: dict[str, str], # mutable-ok: BaseSearchConfig hands providers the mutable request header dict
|
||||
optional_params: dict[str, object], # mutable-ok: BaseSearchConfig passes optional params as a dict
|
||||
headers: dict[str, str],
|
||||
optional_params: dict[str, object],
|
||||
request_data: dict[str, object] | list[dict[str, object]], # mutable-ok: request bodies are JSON dicts
|
||||
api_base: str,
|
||||
api_key: str | None = None,
|
||||
) -> tuple[dict[str, str], bytes | None]: # mutable-ok: BaseSearchConfig.sign_request returns httpx headers
|
||||
) -> tuple[dict[str, str], bytes | None]:
|
||||
"""
|
||||
Authenticate the MCP request.
|
||||
|
||||
|
|
@ -451,7 +451,7 @@ class AgentCoreSearchConfig(BaseSearchConfig, BaseAWSLLM):
|
|||
self,
|
||||
error_message: str,
|
||||
status_code: int,
|
||||
headers: dict, # mutable-ok: BaseSearchConfig.get_error_class takes the response headers as a dict
|
||||
headers: dict,
|
||||
) -> Exception:
|
||||
return BedrockError(
|
||||
status_code=status_code,
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ class BedrockVectorStoreConfig(BaseVectorStoreConfig, BaseAWSLLM):
|
|||
self,
|
||||
error_message: str,
|
||||
status_code: int,
|
||||
headers: dict[str, object] | httpx.Headers, # mutable-ok: base passes response headers as a dict
|
||||
headers: dict[str, object] | httpx.Headers,
|
||||
) -> BedrockError:
|
||||
return BedrockError(status_code=status_code, message=error_message, headers=headers)
|
||||
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ class BedrockMantlePassthroughConfig(BedrockPassthroughConfig):
|
|||
model: str,
|
||||
custom_llm_provider: str,
|
||||
httpx_response: Response,
|
||||
request_data: dict, # mutable-ok: mirrors the inherited BedrockPassthroughConfig signature
|
||||
request_data: dict,
|
||||
logging_obj: Logging,
|
||||
endpoint: str,
|
||||
) -> Optional["CostResponseTypes"]:
|
||||
|
|
|
|||
|
|
@ -164,7 +164,7 @@ def _message_blocks(event: Mapping[str, object]) -> Sequence[object]:
|
|||
message: Final = event.get("message")
|
||||
content: Final = message.get("content") if isinstance(message, Mapping) else None
|
||||
if isinstance(content, str):
|
||||
return ({"type": "text", "text": content},) # mutable-ok: JSON content block, like the stream's
|
||||
return ({"type": "text", "text": content},)
|
||||
return content if isinstance(content, list) else ()
|
||||
|
||||
|
||||
|
|
@ -182,8 +182,7 @@ def _assistant_block_events(block: Mapping[str, Any], state: ClaudeCodeStreamSta
|
|||
id=str(block.get("id", "")),
|
||||
name=normalize_tool_name(native, NATIVE_TO_NORMALIZED),
|
||||
native_name=native,
|
||||
input=block.get("input")
|
||||
or {}, # mutable-ok: ToolCall.input is a dict field; empty default for a missing input
|
||||
input=block.get("input") or {},
|
||||
builtin=not native.startswith("mcp__"),
|
||||
),
|
||||
)
|
||||
|
|
@ -236,7 +235,7 @@ def _record_result(event: Mapping[str, Any], state: ClaudeCodeStreamState) -> Se
|
|||
state.is_error = bool(event.get("is_error", False))
|
||||
result = event.get("result")
|
||||
state.result_text = result if isinstance(result, str) else None
|
||||
state.errors = [str(e) for e in event.get("errors") or ()] # mutable-ok: mirrors the JSON errors array
|
||||
state.errors = [str(e) for e in event.get("errors") or ()]
|
||||
state.structured_output = event.get("structured_output")
|
||||
if event.get("session_id"):
|
||||
state.session_id = str(event["session_id"])
|
||||
|
|
@ -318,7 +317,7 @@ class ClaudeCodeHarnessConfig(BaseCLIHarnessConfig):
|
|||
}
|
||||
)
|
||||
return HarnessSessionSetup(
|
||||
persisted_dirs=[("projects", "claude_code/projects")], # mutable-ok: tests compare to a list
|
||||
persisted_dirs=[("projects", "claude_code/projects")],
|
||||
skills_dir="skills",
|
||||
env=env,
|
||||
)
|
||||
|
|
@ -335,7 +334,7 @@ class ClaudeCodeHarnessConfig(BaseCLIHarnessConfig):
|
|||
schema = ctx.output.model_json_schema() if ctx.output is not None else None
|
||||
system_prompt: Final = build_system_prompt(ctx.instructions, schema)
|
||||
disallowed: Final = native_tool_names(ctx.disable_tools, NORMALIZED_TO_NATIVE)
|
||||
config: Final = dict(options.config) # mutable-ok: json.dumps needs a plain dict
|
||||
config: Final = dict(options.config)
|
||||
settings: Final = json.dumps(config) if config else None
|
||||
argv: Final = (
|
||||
CLAUDE_BINARY,
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ def _tool_input(item: Mapping[str, Any]) -> tuple[str, str, Mapping[str, object]
|
|||
if item_type == "command_execution":
|
||||
return "bash", "command_execution", MappingProxyType({"command": item.get("command", "")}), True
|
||||
if item_type == "file_change":
|
||||
changes: Final = list(item.get("changes") or ()) # mutable-ok: JSON array, as codex reports it
|
||||
changes: Final = list(item.get("changes") or ())
|
||||
return "edit", "apply_patch", MappingProxyType({"changes": changes}), True
|
||||
if item_type == "web_search":
|
||||
return "web_search", "web_search", MappingProxyType({"query": item.get("query", "")}), True
|
||||
|
|
@ -188,7 +188,7 @@ def _config_override(key: object, value: object) -> str:
|
|||
def config_overrides(config: Mapping[str, object]) -> Sequence[str]:
|
||||
"""`-c` override strings for CodexOptions.config, rejecting managed keys."""
|
||||
overrides: Final = (_config_override(key, value) for key, value in config.items())
|
||||
return list(overrides) # mutable-ok: public helper; tests compare to a list
|
||||
return list(overrides)
|
||||
|
||||
|
||||
def _flag_pairs(flag: str, values: Sequence[str]) -> tuple[str, ...]:
|
||||
|
|
@ -232,7 +232,7 @@ class CodexHarnessConfig(BaseCLIHarnessConfig):
|
|||
)
|
||||
return HarnessSessionSetup(
|
||||
files=files,
|
||||
persisted_dirs=[("sessions", "codex/sessions")], # mutable-ok: tests compare to a list
|
||||
persisted_dirs=[("sessions", "codex/sessions")],
|
||||
skills_dir="skills",
|
||||
env=MappingProxyType({**options.env, CODEX_TOKEN_ENV: ctx.endpoint.token, "CODEX_HOME": private_dir}),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ class CohereEmbeddingConfig:
|
|||
self,
|
||||
model: str,
|
||||
input: list[str], # mutable-ok: mirrors override contract
|
||||
inference_params: dict[str, object], # mutable-ok: mirrors override contract
|
||||
inference_params: dict[str, object],
|
||||
) -> CohereEmbeddingRequestWithModel:
|
||||
return self._transform_request(model, input, inference_params)
|
||||
|
||||
|
|
@ -136,7 +136,7 @@ class CohereEmbeddingConfig:
|
|||
response: httpx.Response,
|
||||
api_key: str | None,
|
||||
logging_obj: LiteLLMLoggingObj,
|
||||
data: dict[str, object] | CohereEmbeddingRequest, # mutable-ok: mirrors override contract
|
||||
data: dict[str, object] | CohereEmbeddingRequest,
|
||||
model_response: EmbeddingResponse,
|
||||
model: str,
|
||||
encoding: _SupportsEncode,
|
||||
|
|
@ -202,7 +202,7 @@ class CohereEmbeddingConfig:
|
|||
|
||||
def populate_embedding_response(
|
||||
self,
|
||||
response_json: dict[str, object], # mutable-ok: mirrors override contract
|
||||
response_json: dict[str, object],
|
||||
model_response: EmbeddingResponse,
|
||||
model: str,
|
||||
encoding: _SupportsEncode,
|
||||
|
|
|
|||
|
|
@ -283,26 +283,26 @@ class _MediaUploadKwargs(TypedDict, total=False):
|
|||
class _AsyncFilesEnvironmentValidator(Protocol):
|
||||
async def avalidate_environment(
|
||||
self,
|
||||
headers: dict, # mutable-ok: mirrors the sync validate_environment contract this overrides
|
||||
headers: dict,
|
||||
model: str,
|
||||
messages: list, # mutable-ok: mirrors the sync validate_environment contract this overrides
|
||||
optional_params: dict, # mutable-ok: mirrors the sync validate_environment contract this overrides
|
||||
litellm_params: dict, # mutable-ok: mirrors the sync validate_environment contract this overrides
|
||||
optional_params: dict,
|
||||
litellm_params: dict,
|
||||
api_key: str | None = None,
|
||||
api_base: str | None = None,
|
||||
) -> dict: ... # mutable-ok: mirrors the sync validate_environment contract this overrides
|
||||
) -> dict: ...
|
||||
|
||||
|
||||
async def _avalidate_files_environment(
|
||||
provider_config: BaseFilesConfig | BaseBatchesConfig,
|
||||
*,
|
||||
headers: dict, # mutable-ok: mirrors the sync validate_environment contract this overrides
|
||||
headers: dict,
|
||||
model: str,
|
||||
messages: list, # mutable-ok: mirrors the sync validate_environment contract this overrides
|
||||
optional_params: dict, # mutable-ok: mirrors the sync validate_environment contract this overrides
|
||||
litellm_params: dict, # mutable-ok: mirrors the sync validate_environment contract this overrides
|
||||
optional_params: dict,
|
||||
litellm_params: dict,
|
||||
api_key: str | None,
|
||||
) -> dict: # mutable-ok: mirrors the sync validate_environment contract this overrides
|
||||
) -> dict:
|
||||
"""Await the provider's async credential hook when it has one (e.g. Anthropic's workload
|
||||
identity token exchange); otherwise offload the sync hook to a worker thread. Either way
|
||||
the caller, an async file handler, never blocks the event loop on it."""
|
||||
|
|
@ -736,8 +736,8 @@ class BaseLLMHTTPHandler:
|
|||
)
|
||||
|
||||
def sign_and_log(
|
||||
transformed: dict[str, object], # mutable-ok: async_completion takes dict
|
||||
) -> tuple[dict[str, object], dict[str, object], bytes | None]: # mutable-ok: async_completion takes dict
|
||||
transformed: dict[str, object],
|
||||
) -> tuple[dict[str, object], dict[str, object], bytes | None]:
|
||||
data: Final = (
|
||||
{
|
||||
**transformed,
|
||||
|
|
@ -778,8 +778,8 @@ class BaseLLMHTTPHandler:
|
|||
return data, signed[0], signed[1]
|
||||
|
||||
def dispatch_async(
|
||||
data: dict[str, object], # mutable-ok: async_completion takes dict
|
||||
signed_headers: dict[str, object], # mutable-ok: async_completion takes dict
|
||||
data: dict[str, object],
|
||||
signed_headers: dict[str, object],
|
||||
signed_json_body: bytes | None,
|
||||
) -> Coroutine[object, object, ModelResponse | CustomStreamWrapper]:
|
||||
async_client: Final = client if isinstance(client, AsyncHTTPHandler) else None
|
||||
|
|
@ -3569,9 +3569,9 @@ class BaseLLMHTTPHandler:
|
|||
self,
|
||||
*,
|
||||
create_file_data: CreateFileRequest,
|
||||
litellm_params: dict, # mutable-ok: mirrors the create_file contract this dispatches for
|
||||
litellm_params: dict,
|
||||
provider_config: BaseFilesConfig,
|
||||
headers: dict, # mutable-ok: mirrors the create_file contract this dispatches for
|
||||
headers: dict,
|
||||
api_base: str | None,
|
||||
api_key: str | None,
|
||||
logging_obj: LiteLLMLoggingObj,
|
||||
|
|
@ -4046,9 +4046,9 @@ class BaseLLMHTTPHandler:
|
|||
self,
|
||||
*,
|
||||
create_batch_data: "CreateBatchRequest",
|
||||
litellm_params: dict, # mutable-ok: mirrors the create_batch contract this dispatches for
|
||||
litellm_params: dict,
|
||||
provider_config: "BaseBatchesConfig",
|
||||
headers: dict, # mutable-ok: mirrors the create_batch contract this dispatches for
|
||||
headers: dict,
|
||||
api_base: str | None,
|
||||
api_key: str | None,
|
||||
logging_obj: "LiteLLMLoggingObj",
|
||||
|
|
@ -4980,8 +4980,8 @@ class BaseLLMHTTPHandler:
|
|||
first_page: httpx.Response,
|
||||
provider_config: BaseFilesConfig,
|
||||
logging_obj: LiteLLMLoggingObj,
|
||||
litellm_params: dict, # mutable-ok: handed to the files contract, which types it as a dict
|
||||
headers: dict, # mutable-ok: handed to validate_environment, which types it as a dict
|
||||
litellm_params: dict,
|
||||
headers: dict,
|
||||
client: HTTPHandler,
|
||||
timeout: float | httpx.Timeout | None,
|
||||
) -> Iterator[list[OpenAIFileObject]]: # mutable-ok: each page arrives as the list the files contract returns
|
||||
|
|
@ -5008,8 +5008,8 @@ class BaseLLMHTTPHandler:
|
|||
first_page: httpx.Response,
|
||||
provider_config: BaseFilesConfig,
|
||||
logging_obj: LiteLLMLoggingObj,
|
||||
litellm_params: dict, # mutable-ok: handed to the files contract, which types it as a dict
|
||||
headers: dict, # mutable-ok: handed to validate_environment, which types it as a dict
|
||||
litellm_params: dict,
|
||||
headers: dict,
|
||||
client: AsyncHTTPHandler,
|
||||
timeout: float | httpx.Timeout | None,
|
||||
) -> AsyncIterator[list[OpenAIFileObject]]: # mutable-ok: each page arrives as the list the files contract returns
|
||||
|
|
@ -5034,9 +5034,9 @@ class BaseLLMHTTPHandler:
|
|||
def _next_listing_page_headers(
|
||||
self,
|
||||
provider_config: BaseFilesConfig,
|
||||
headers: dict, # mutable-ok: handed to validate_environment, which types it as a dict
|
||||
litellm_params: dict, # mutable-ok: handed to the files contract, which types it as a dict
|
||||
) -> dict: # mutable-ok: validate_environment returns the header dict the files contract types
|
||||
headers: dict,
|
||||
litellm_params: dict,
|
||||
) -> dict:
|
||||
return provider_config.validate_environment(
|
||||
api_key=litellm_params.get("api_key"),
|
||||
headers=headers,
|
||||
|
|
@ -5050,9 +5050,9 @@ class BaseLLMHTTPHandler:
|
|||
self,
|
||||
latest_page: httpx.Response,
|
||||
provider_config: BaseFilesConfig,
|
||||
litellm_params: dict, # mutable-ok: handed to the files contract, which types it as a dict
|
||||
litellm_params: dict,
|
||||
listed_count: int,
|
||||
) -> tuple[str, dict[str, str]] | None: # mutable-ok: the base files contract returns the query as a dict
|
||||
) -> tuple[str, dict[str, str]] | None:
|
||||
if listed_count >= MAX_FILE_LIST_LIMIT:
|
||||
return None
|
||||
return provider_config.transform_list_files_next_request(
|
||||
|
|
|
|||
|
|
@ -314,7 +314,7 @@ class SandboxBackend(SandboxBackendProtocol): # pyright: ignore[reportUntypedBa
|
|||
except (InvalidGlobPatternError, ValueError, SandboxError) as e:
|
||||
return GlobResult(error=str(e), matches=None)
|
||||
if done.exit_code != 0 and not done.stdout:
|
||||
return GlobResult(matches=[]) # mutable-ok: deepagents GlobResult.matches is typed list[FileInfo]
|
||||
return GlobResult(matches=[])
|
||||
matches = sorted(
|
||||
(
|
||||
FileInfo(path=self.to_virtual(real), is_dir=False)
|
||||
|
|
@ -353,9 +353,7 @@ class SandboxBackend(SandboxBackendProtocol): # pyright: ignore[reportUntypedBa
|
|||
return GrepResult(error=f"Path '{path or '/'}': {e}")
|
||||
if done.exit_code not in (0, 1) and not done.stdout:
|
||||
return GrepResult(error=f"Path '{path or '/'}': {done.stderr.strip() or 'grep failed'}")
|
||||
matches = list( # mutable-ok: GrepResult.matches is list[GrepMatch]
|
||||
self._grep_matches(done.stdout, root, include)
|
||||
)
|
||||
matches = list(self._grep_matches(done.stdout, root, include))
|
||||
if max_count is not None and len(matches) > max_count:
|
||||
return GrepResult(matches=matches[:max_count], truncated=True)
|
||||
return GrepResult(matches=matches)
|
||||
|
|
@ -385,9 +383,7 @@ class SandboxBackend(SandboxBackendProtocol): # pyright: ignore[reportUntypedBa
|
|||
self,
|
||||
files: list[tuple[str, bytes]], # mutable-ok: signature fixed by deepagents BackendProtocol
|
||||
) -> list[FileUploadResponse]: # mutable-ok: return type fixed by deepagents BackendProtocol
|
||||
return [ # mutable-ok: BackendProtocol returns a list
|
||||
await self._upload_one(path, data) for path, data in files
|
||||
]
|
||||
return [await self._upload_one(path, data) for path, data in files]
|
||||
|
||||
def upload_files(
|
||||
self,
|
||||
|
|
@ -407,7 +403,7 @@ class SandboxBackend(SandboxBackendProtocol): # pyright: ignore[reportUntypedBa
|
|||
self,
|
||||
paths: list[str], # mutable-ok: signature fixed by deepagents BackendProtocol
|
||||
) -> list[FileDownloadResponse]: # mutable-ok: return type fixed by deepagents BackendProtocol
|
||||
return [await self._download_one(path) for path in paths] # mutable-ok: BackendProtocol returns a list
|
||||
return [await self._download_one(path) for path in paths]
|
||||
|
||||
def download_files(
|
||||
self,
|
||||
|
|
@ -464,11 +460,7 @@ class ToolFilterMiddleware(AgentMiddleware): # pyright: ignore[reportUntypedBas
|
|||
return _FILTER_MIDDLEWARE_NAME
|
||||
|
||||
def _filtered(self, request: ModelRequest) -> ModelRequest:
|
||||
return request.override(
|
||||
tools=[ # mutable-ok: ModelRequest.tools is a list
|
||||
t for t in request.tools if _tool_name(t) not in self._blocked
|
||||
]
|
||||
)
|
||||
return request.override(tools=[t for t in request.tools if _tool_name(t) not in self._blocked])
|
||||
|
||||
def wrap_model_call(
|
||||
self, request: ModelRequest, handler: Callable[[ModelRequest], ModelResponse]
|
||||
|
|
|
|||
|
|
@ -73,18 +73,18 @@ _APPROVAL_DECISIONS: Final = ("approve", "reject")
|
|||
|
||||
def chat_model_kwargs(
|
||||
ctx: SessionContext,
|
||||
) -> dict[str, Any]: # mutable-ok: ChatLiteLLM constructor kwargs, splatted as **kwargs
|
||||
) -> dict[str, Any]:
|
||||
"""ChatLiteLLM constructor kwargs for gateway or SDK mode."""
|
||||
if not ctx.model:
|
||||
raise ValueError("Harness.DEEPAGENTS needs model=")
|
||||
if ctx.gateway is not None:
|
||||
return { # mutable-ok: ChatLiteLLM constructor kwargs, splatted as **kwargs
|
||||
return {
|
||||
"model": f"litellm_proxy/{ctx.model}",
|
||||
"api_base": ctx.gateway.api_base,
|
||||
"api_key": ctx.gateway.api_key,
|
||||
"extra_headers": gateway_headers(ctx),
|
||||
}
|
||||
return {"model": ctx.model, "api_key": ctx.api_key, "api_base": ctx.api_base} # mutable-ok: ChatLiteLLM kwargs
|
||||
return {"model": ctx.model, "api_key": ctx.api_key, "api_base": ctx.api_base}
|
||||
|
||||
|
||||
def native_tool_name(name: str) -> str:
|
||||
|
|
@ -105,16 +105,11 @@ def blocked_tools(permissions: str, disable_tools: Sequence[str]) -> frozenset[s
|
|||
return disabled
|
||||
|
||||
|
||||
def interrupt_config(
|
||||
permissions: str, blocked: frozenset[str]
|
||||
) -> dict[str, Any] | None: # mutable-ok: deepagents create_deep_agent(interrupt_on=) takes a dict
|
||||
def interrupt_config(permissions: str, blocked: frozenset[str]) -> dict[str, Any] | None:
|
||||
"""interrupt_on for permissions='ask': approve/reject every mutating built-in."""
|
||||
if permissions != "ask":
|
||||
return None
|
||||
return { # mutable-ok: deepagents interrupt_on config (dict of InterruptOnConfig with list allowed_decisions)
|
||||
name: {"allowed_decisions": list(_APPROVAL_DECISIONS)} # mutable-ok: deepagents InterruptOnConfig shape
|
||||
for name in sorted(APPROVAL_TOOLS - blocked)
|
||||
}
|
||||
return {name: {"allowed_decisions": list(_APPROVAL_DECISIONS)} for name in sorted(APPROVAL_TOOLS - blocked)}
|
||||
|
||||
|
||||
def recursion_limit(ctx: SessionContext) -> int:
|
||||
|
|
@ -162,12 +157,12 @@ def stream_events(
|
|||
) -> list[Event]: # mutable-ok: returns a list; existing callers/tests compare it to list literals
|
||||
"""Text / Reasoning deltas for one streamed message chunk."""
|
||||
if getattr(message, "type", None) not in ("AIMessageChunk", "ai"):
|
||||
return [] # mutable-ok: returns a list; existing callers/tests compare it to list literals
|
||||
return []
|
||||
reasoning = reasoning_text(message)
|
||||
text = content_text(getattr(message, "content", ""))
|
||||
reasoning_events: tuple[Event, ...] = (Reasoning(delta=reasoning),) if reasoning else ()
|
||||
text_events: tuple[Event, ...] = (Text(delta=text),) if text else ()
|
||||
return [ # mutable-ok: returns a list; existing callers/tests compare it to list literals
|
||||
return [
|
||||
*reasoning_events,
|
||||
*text_events,
|
||||
]
|
||||
|
|
@ -180,7 +175,7 @@ def tool_call_event(call: Mapping[str, object]) -> ToolCall:
|
|||
id=str(call.get("id") or ""),
|
||||
name=normalized_tool_name(native),
|
||||
native_name=native,
|
||||
input=dict(args) if isinstance(args, Mapping) else {"args": args}, # mutable-ok: ToolCall.input is a dict
|
||||
input=dict(args) if isinstance(args, Mapping) else {"args": args},
|
||||
builtin=native in BUILTIN_TOOLS,
|
||||
)
|
||||
|
||||
|
|
@ -199,8 +194,8 @@ def update_events(
|
|||
) -> list[Event]: # mutable-ok: returns a list; existing callers/tests compare it to list literals
|
||||
"""ToolCall / ToolResult events from one `updates` stream chunk (node -> state delta)."""
|
||||
if not isinstance(update, Mapping):
|
||||
return [] # mutable-ok: returns a list; existing callers/tests compare it to list literals
|
||||
return list( # mutable-ok: returns a list; existing callers/tests compare it to list literals
|
||||
return []
|
||||
return list(
|
||||
itertools.chain.from_iterable(_message_events(message, skip_tools) for message in _node_messages(update))
|
||||
)
|
||||
|
||||
|
|
@ -225,10 +220,10 @@ def interrupts_in(
|
|||
update: object,
|
||||
) -> list[Any]: # mutable-ok: returns a list; existing callers/tests compare it to list literals
|
||||
if not isinstance(update, Mapping):
|
||||
return [] # mutable-ok: returns a list; existing callers/tests compare it to list literals
|
||||
return []
|
||||
found = update.get("__interrupt__")
|
||||
items = tuple(found) if isinstance(found, (list, tuple)) else ()
|
||||
return list(items) # mutable-ok: list return; callers/tests compare to lists
|
||||
return list(items)
|
||||
|
||||
|
||||
def final_ai_text(messages: Sequence[object]) -> str:
|
||||
|
|
@ -254,16 +249,16 @@ def approval_requests(
|
|||
) -> list[Mapping[str, Any]]: # mutable-ok: returns a list; existing callers/tests compare it to list literals
|
||||
"""action_requests of a HumanInTheLoopMiddleware interrupt payload."""
|
||||
if not isinstance(interrupt_value, Mapping):
|
||||
return [] # mutable-ok: returns a list; existing callers/tests compare it to list literals
|
||||
return []
|
||||
requests = interrupt_value.get("action_requests")
|
||||
kept = tuple(r for r in requests if isinstance(r, Mapping)) if isinstance(requests, list) else ()
|
||||
return list(kept) # mutable-ok: list return; callers/tests compare to lists
|
||||
return list(kept)
|
||||
|
||||
|
||||
def decision(allowed: bool, reason: str) -> dict[str, Any]: # mutable-ok: LangGraph resume payload (HITL decision dict)
|
||||
def decision(allowed: bool, reason: str) -> dict[str, Any]:
|
||||
if allowed:
|
||||
return {"type": "approve"} # mutable-ok: LangGraph resume payload (HITL decision dict)
|
||||
return { # mutable-ok: LangGraph HITL decision
|
||||
return {"type": "approve"}
|
||||
return {
|
||||
"type": "reject",
|
||||
"message": reason or "The user denied this tool call.",
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue