Files
wehub-resource-sync 4b6817381b
CI (OpenClaw E2E) / openclaw test (push) Has been cancelled
CI / coverage-report (push) Has been cancelled
CI / test-kubernetes (push) Has been cancelled
CI / should-run-thorough (push) Has been cancelled
CI / test-thorough (cloudwatch-demo) (push) Has been cancelled
CI / test-thorough (flink-ecs) (push) Has been cancelled
CI / test-thorough (upstream-lambda) (push) Has been cancelled
CI / test-thorough (prefect-ecs-fargate) (push) Has been cancelled
Release / build-binaries (zip, opensre.exe, onefile, windows-latest, windows-x64) (push) Has been cancelled
Benchmark image — build + push to ECR (any adapter) / build + push (push) Has been cancelled
CI / quality (ubuntu-latest) (push) Has been cancelled
CI / test (tools-runtime) (push) Has been cancelled
CI / test (e2e-general) (push) Has been cancelled
CI / test (cli-runtime) (push) Has been cancelled
CI / test (e2e-provider-and-openclaw) (push) Has been cancelled
CI / test (integrations-and-misc) (push) Has been cancelled
Release / verify (push) Has been cancelled
Release / build-python-dist (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, macos-15-intel, darwin-x64) (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, macos-latest, darwin-arm64) (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, ubuntu-22.04, linux-x64) (push) Has been cancelled
Release / publish-release (push) Has been cancelled
Release / publish-main-release (push) Has been cancelled
Interactive Shell Live (PR + post-merge) / turn-checks (no-LLM) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Interactive Shell Live (PR + post-merge) / turn-live shard ${{ matrix.shard_index }} (push) Has been cancelled
Release / prepare (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, ubuntu-22.04-arm, linux-arm64) (push) Has been cancelled
Synthetic Deterministic Tests / Synthetic offline (deterministic) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:10:45 +08:00

76 lines
2.2 KiB
Python

"""Observe LLM usage during a foreground investigation for turn telemetry."""
from __future__ import annotations
import contextlib
from collections.abc import Iterator
from dataclasses import dataclass
from core.llm.shared.usage import set_usage_hook
@dataclass
class InvestigationLlmUsage:
"""Accumulated provider-reported LLM usage for one investigation run."""
model: str = ""
input_tokens: int = 0
output_tokens: int = 0
@property
def observed(self) -> bool:
return bool(self.model) or self.input_tokens > 0 or self.output_tokens > 0
@contextlib.contextmanager
def observe_investigation_llm_usage() -> Iterator[InvestigationLlmUsage]:
"""Accumulate provider-reported token usage while the body runs.
Registration is best-effort: if another owner already holds the process-wide
usage hook (`core.llm.shared.usage.set_usage_hook`), the investigation proceeds
without usage observation rather than failing.
"""
usage = InvestigationLlmUsage()
def _hook(model: str, tokens_in: int, tokens_out: int) -> None:
if model:
usage.model = model
usage.input_tokens += tokens_in
usage.output_tokens += tokens_out
registered = False
with contextlib.suppress(RuntimeError):
set_usage_hook(_hook)
registered = True
try:
yield usage
finally:
if registered:
set_usage_hook(None)
def resolve_configured_llm_identity() -> tuple[str, str]:
"""Best-effort ``(provider, model)`` from the configured LLM settings."""
try:
from config.config import resolve_llm_settings
from config.llm_auth.auth_method import (
effective_llm_provider,
get_configured_llm_auth_method,
)
settings = resolve_llm_settings()
provider = effective_llm_provider(
settings.provider, get_configured_llm_auth_method(settings.provider)
)
model = str(getattr(settings, f"{provider}_reasoning_model", "") or "")
return provider, model
except Exception:
return "", ""
__all__ = [
"InvestigationLlmUsage",
"observe_investigation_llm_usage",
"resolve_configured_llm_identity",
]