Download src/sr_harness/core/api.py from YuMeow/SRHarness: direct link, hf CLI and curl.
- Browser
- Download file 4.51 kB
-
https://huggingface.co/spaces/YuMeow/SRHarness/resolve/main/src/sr_harness/core/api.py
- Command line
-
hf download hf://spaces/YuMeow/SRHarness/src/sr_harness/core/api.py
-
curl -L -o api.py https://huggingface.co/spaces/YuMeow/SRHarness/resolve/main/src/sr_harness/core/api.py
4.51 kB
| # Copyright (c) 2026-present, Yumeow. Licensed under the MIT License. | |
| from __future__ import annotations | |
| from dataclasses import dataclass, field | |
| from typing import Any, Iterator | |
| from .tool import ToolCall | |
| class APICallSample: | |
| """One complete assistant sample returned by a model provider. | |
| ``message_extra`` contains provider message fields not represented by the | |
| normalized content and tool calls. The :attr:`message` | |
| property reconstructs a provider-compatible assistant message without | |
| retaining a duplicate raw message object. | |
| """ | |
| content: str | None | |
| finish_reason: str | None | |
| _tool_calls: list[ToolCall] = field(default_factory=list, repr=False) | |
| message_extra: dict[str, Any] = field(default_factory=dict) | |
| def __init__( | |
| self, | |
| content: str | None, | |
| tool_calls: list[ToolCall] | None = None, | |
| message_extra: dict[str, Any] | None = None, | |
| finish_reason: str | None = None, | |
| ) -> None: | |
| self.content = content | |
| self.finish_reason = finish_reason | |
| self._tool_calls = tool_calls if tool_calls is not None else [] | |
| self.message_extra = dict(message_extra or {}) | |
| def tool_calls(self) -> list[ToolCall]: | |
| """Return the normalized tool calls used to construct this response.""" | |
| return self._tool_calls | |
| def reasoning(self) -> Any: | |
| """Return provider reasoning without imposing one provider field name.""" | |
| if self.message_extra.get("reasoning"): | |
| return self.message_extra["reasoning"] | |
| if self.message_extra.get("reasoning_content"): | |
| return self.message_extra["reasoning_content"] | |
| return "".join( | |
| item.get("text") or "" | |
| for item in (self.message_extra.get("reasoning_details") or []) | |
| if isinstance(item, dict) | |
| ) or None | |
| def truncated(self) -> bool: | |
| """Whether this sample ended at the provider's output limit.""" | |
| return self.finish_reason in {"length", "max_tokens", "max_output_tokens", "MAX_TOKENS"} | |
| def message(self) -> dict[str, Any]: | |
| """Reconstruct the assistant message represented by this response.""" | |
| message = {**self.message_extra, "content": self.content} | |
| raw_tool_calls = [call.raw for call in self.tool_calls if isinstance(call.raw, dict)] | |
| if raw_tool_calls and "tool_calls" not in message: | |
| message["tool_calls"] = raw_tool_calls | |
| message.setdefault("role", "assistant") | |
| return message | |
| class APICallSummary: | |
| """ | |
| Wrapper for LLM generator that captures the return value. | |
| Example: | |
| >>> api = OpenAIAPI(model='gpt-4o-mini') | |
| >>> result = api("Hello", n=3) # Returns APICallSummary | |
| >>> for response in result: | |
| ... print(response.content, response.tool_calls) | |
| >>> print(result.ok, result.error) | |
| >>> print(result.token_usage, result.money_usage) | |
| """ | |
| gen: Iterator[APICallSample] | |
| yielded: list[APICallSample] = field(default_factory=list, init=False) | |
| ok: bool | None = field(default=None, init=False) | |
| error: str | None = field(default=None, init=False) | |
| token_usage: dict[str, float] = field(default_factory=dict, init=False) | |
| money_usage: dict[str, float] = field(default_factory=dict, init=False) | |
| extra: dict[str, Any] = field(default_factory=dict, init=False) | |
| def truncated(self) -> bool: | |
| """Whether any returned sample reached its output limit.""" | |
| return any(sample.truncated for sample in self.yielded) | |
| def __iter__(self): | |
| """Iterate over the generated contents.""" | |
| try: | |
| while True: | |
| response = next(self.gen) | |
| if not isinstance(response, APICallSample): | |
| raise TypeError( | |
| "API providers must yield APICallSample instances, " | |
| f"not {type(response).__name__}" | |
| ) | |
| self.yielded.append(response) | |
| yield response | |
| except StopIteration as e: | |
| result = e.value or {} | |
| self.ok = bool(result.get("ok", True)) | |
| self.error = result.get("error") | |
| self.token_usage = dict(result.get("token_usage") or {}) | |
| self.money_usage = dict(result.get("money_usage") or {}) | |
| self.extra = dict(result.get("extra") or {}) | |