otto-cli-agent 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- agent/README.md +22 -0
- agent/__init__.py +0 -0
- agent/cli/README.md +77 -0
- agent/cli/__init__.py +0 -0
- agent/cli/art.py +371 -0
- agent/cli/chat.py +309 -0
- agent/cli/clipboard.py +106 -0
- agent/cli/context.py +56 -0
- agent/cli/doctor.py +60 -0
- agent/cli/errors.py +58 -0
- agent/cli/eval.py +130 -0
- agent/cli/eval_claw.py +414 -0
- agent/cli/eval_compaction.py +106 -0
- agent/cli/eval_hle.py +92 -0
- agent/cli/eval_memory.py +253 -0
- agent/cli/eval_swe.py +172 -0
- agent/cli/lessons.py +97 -0
- agent/cli/main.py +67 -0
- agent/cli/modals.py +570 -0
- agent/cli/models.py +64 -0
- agent/cli/output.py +54 -0
- agent/cli/route.py +78 -0
- agent/cli/sessions.py +125 -0
- agent/cli/setup_screen.py +562 -0
- agent/cli/shell.py +548 -0
- agent/cli/tui.py +1807 -0
- agent/cli/ui.py +14 -0
- agent/cli/usage_panel.py +159 -0
- agent/config/README.md +7 -0
- agent/config/__init__.py +0 -0
- agent/config/envfile.py +76 -0
- agent/eval/README.md +76 -0
- agent/eval/__init__.py +0 -0
- agent/eval/claw_bench.py +1031 -0
- agent/eval/compaction_bench.py +229 -0
- agent/eval/data/README.md +10 -0
- agent/eval/data/claw/README.md +108 -0
- agent/eval/data/claw/llm_judge-gemini.patch +57 -0
- agent/eval/data/claw/otto.yaml +35 -0
- agent/eval/failures.py +276 -0
- agent/eval/golden/README.md +33 -0
- agent/eval/golden/code_01.json +6 -0
- agent/eval/golden/code_02.json +6 -0
- agent/eval/golden/code_03.json +6 -0
- agent/eval/golden/code_04.json +6 -0
- agent/eval/golden/code_05.json +6 -0
- agent/eval/golden/code_06.json +6 -0
- agent/eval/golden/math_01.json +6 -0
- agent/eval/golden/math_02.json +6 -0
- agent/eval/golden/math_03.json +6 -0
- agent/eval/golden/math_04.json +6 -0
- agent/eval/golden/math_05.json +6 -0
- agent/eval/golden/math_06.json +6 -0
- agent/eval/golden/nphard_gcp_01.json +6 -0
- agent/eval/golden/nphard_ksp_01.json +6 -0
- agent/eval/golden/nphard_math_binpacking_01.json +6 -0
- agent/eval/golden/nphard_math_clique_01.json +6 -0
- agent/eval/golden/nphard_math_setcover_01.json +6 -0
- agent/eval/golden/nphard_math_subsetsum_01.json +6 -0
- agent/eval/golden/nphard_tsp_01.json +6 -0
- agent/eval/golden/nphard_tsp_02.json +6 -0
- agent/eval/hle_bench.py +273 -0
- agent/eval/langfuse_sync.py +172 -0
- agent/eval/memory_bench.py +538 -0
- agent/eval/runner.py +174 -0
- agent/eval/single_agent.py +120 -0
- agent/eval/swe_bench.py +604 -0
- agent/eval/terminal_bench.py +345 -0
- agent/memory/README.md +102 -0
- agent/memory/__init__.py +42 -0
- agent/memory/embeddings.py +302 -0
- agent/memory/hashing.py +15 -0
- agent/memory/lessons.py +483 -0
- agent/memory/queue.py +531 -0
- agent/memory/retrieval.py +493 -0
- agent/memory/session.py +60 -0
- agent/memory/sessions.py +436 -0
- agent/memory/store.py +429 -0
- agent/memory/tokens.py +60 -0
- agent/memory/wiring.py +146 -0
- agent/pipeline/README.md +135 -0
- agent/pipeline/__init__.py +0 -0
- agent/pipeline/browsing.py +609 -0
- agent/pipeline/budget.py +403 -0
- agent/pipeline/codemap.py +254 -0
- agent/pipeline/evidence.py +325 -0
- agent/pipeline/execution.py +67 -0
- agent/pipeline/modes.py +137 -0
- agent/pipeline/native.py +1137 -0
- agent/pipeline/nodes.py +3644 -0
- agent/pipeline/pricing.py +209 -0
- agent/pipeline/progress.py +139 -0
- agent/pipeline/rag.py +139 -0
- agent/pipeline/research.py +1325 -0
- agent/pipeline/run.py +528 -0
- agent/pipeline/screen.py +77 -0
- agent/pipeline/state.py +220 -0
- agent/pipeline/toolkit.py +328 -0
- agent/pipeline/tools.py +1990 -0
- agent/pipeline/tracing.py +147 -0
- agent/pipeline/usage.py +251 -0
- agent/pipeline/vision.py +84 -0
- agent/pipeline/walkthrough.py +735 -0
- agent/pipeline/workspace.py +229 -0
- agent/router/README.md +60 -0
- agent/router/__init__.py +0 -0
- agent/router/automap.py +114 -0
- agent/router/health.py +229 -0
- agent/router/llm_provider/README.md +38 -0
- agent/router/llm_provider/__init__.py +202 -0
- agent/router/llm_provider/anthropic_provider.py +128 -0
- agent/router/llm_provider/base.py +507 -0
- agent/router/llm_provider/custom.py +152 -0
- agent/router/llm_provider/gemini_provider.py +122 -0
- agent/router/llm_provider/inception_provider.py +687 -0
- agent/router/llm_provider/openai_provider.py +151 -0
- agent/router/llm_provider/retired.py +145 -0
- agent/router/llm_provider/temperature.py +371 -0
- agent/router/mapping.py +579 -0
- agent/router/outcomes.py +363 -0
- agent/router/overrides.py +389 -0
- agent/router/reload.py +28 -0
- agent/router/router.py +413 -0
- agent/router/setup.py +123 -0
- otto_cli_agent-0.1.0.dist-info/METADATA +115 -0
- otto_cli_agent-0.1.0.dist-info/RECORD +129 -0
- otto_cli_agent-0.1.0.dist-info/WHEEL +4 -0
- otto_cli_agent-0.1.0.dist-info/entry_points.txt +2 -0
- otto_cli_agent-0.1.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"""Gemini provider, on the `google-genai` SDK.
|
|
2
|
+
|
|
3
|
+
Note this is `google-genai` (``from google import genai``), not the legacy
|
|
4
|
+
`google-generativeai` package -- the two have incompatible APIs and the newer
|
|
5
|
+
one is what `langchain-google-genai` pulls in here.
|
|
6
|
+
|
|
7
|
+
As with Anthropic: SDK for discovery, `ChatGoogleGenerativeAI` for chat.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
from typing import Any
|
|
13
|
+
|
|
14
|
+
import httpx
|
|
15
|
+
from google import genai
|
|
16
|
+
from google.genai import errors as genai_errors
|
|
17
|
+
from langchain_core.language_models import BaseChatModel
|
|
18
|
+
from langchain_google_genai import ChatGoogleGenerativeAI
|
|
19
|
+
|
|
20
|
+
from agent.router.llm_provider.base import (
|
|
21
|
+
AuthError,
|
|
22
|
+
BaseProvider,
|
|
23
|
+
Capability,
|
|
24
|
+
ModelInfo,
|
|
25
|
+
ProviderError,
|
|
26
|
+
ProviderUnavailable,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
__all__ = ["GeminiProvider"]
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _translate(exc: Exception) -> ProviderError:
|
|
33
|
+
if isinstance(exc, genai_errors.APIError):
|
|
34
|
+
code = getattr(exc, "code", None)
|
|
35
|
+
if code in (401, 403):
|
|
36
|
+
return AuthError(f"gemini: HTTP {code}")
|
|
37
|
+
return ProviderError(f"gemini: HTTP {code}: {exc}")
|
|
38
|
+
if isinstance(exc, httpx.TransportError):
|
|
39
|
+
# The SDK only wraps HTTP-level failures; DNS, TLS and timeout errors
|
|
40
|
+
# arrive as raw httpx exceptions and would otherwise reach health_check
|
|
41
|
+
# untranslated.
|
|
42
|
+
return ProviderUnavailable(f"gemini: {exc}")
|
|
43
|
+
return ProviderError(f"gemini: {exc}")
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
#: `Model.supported_actions` values that matter to us. This is the only
|
|
47
|
+
#: capability metadata Gemini publishes.
|
|
48
|
+
_ACTION_MAP: dict[str, Capability] = {
|
|
49
|
+
"generateContent": Capability.CHAT,
|
|
50
|
+
"embedContent": Capability.EMBEDDINGS,
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _capabilities_of(model: Any, model_id: str) -> set[Capability]:
|
|
55
|
+
caps = {
|
|
56
|
+
_ACTION_MAP[action]
|
|
57
|
+
for action in (model.supported_actions or [])
|
|
58
|
+
if action in _ACTION_MAP
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
# Gemini publishes no tool-use or modality flags, so these two are a
|
|
62
|
+
# heuristic -- flagged as such, exactly like the OpenAI classifier. Every
|
|
63
|
+
# current gemini-* model does function calling and image input; the
|
|
64
|
+
# gemma-*, embedding-* and aqa entries in the same list do not.
|
|
65
|
+
if Capability.CHAT in caps and model_id.startswith("gemini-"):
|
|
66
|
+
caps |= {Capability.TOOLS, Capability.VISION,
|
|
67
|
+
Capability.STRUCTURED_OUTPUT, Capability.REASONING}
|
|
68
|
+
|
|
69
|
+
return caps
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class GeminiProvider(BaseProvider):
|
|
73
|
+
name = "gemini"
|
|
74
|
+
env_var = "GEMINI_API_KEY"
|
|
75
|
+
default_base_url = None
|
|
76
|
+
capabilities = frozenset(
|
|
77
|
+
{
|
|
78
|
+
Capability.CHAT,
|
|
79
|
+
Capability.TOOLS,
|
|
80
|
+
Capability.VISION,
|
|
81
|
+
Capability.STRUCTURED_OUTPUT,
|
|
82
|
+
Capability.EMBEDDINGS,
|
|
83
|
+
}
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
def _build_client(self) -> genai.Client:
|
|
87
|
+
# Explicit key: the SDK would otherwise fall back to GOOGLE_API_KEY or
|
|
88
|
+
# GEMINI_API_KEY on its own, which makes it ambiguous which one won.
|
|
89
|
+
return genai.Client(api_key=self._api_key)
|
|
90
|
+
|
|
91
|
+
def _fetch_models(self) -> list[ModelInfo]:
|
|
92
|
+
try:
|
|
93
|
+
# The Pager auto-fetches subsequent pages while iterating; page_size
|
|
94
|
+
# only controls how many round trips that takes.
|
|
95
|
+
models = list(self._client.models.list(config={"page_size": 100}))
|
|
96
|
+
except Exception as exc:
|
|
97
|
+
raise _translate(exc) from exc
|
|
98
|
+
|
|
99
|
+
found: list[ModelInfo] = []
|
|
100
|
+
for model in models:
|
|
101
|
+
# `name` arrives as "models/gemini-2.5-pro"; the bare id is what
|
|
102
|
+
# every other API surface expects.
|
|
103
|
+
model_id = (model.name or "").removeprefix("models/")
|
|
104
|
+
if not model_id:
|
|
105
|
+
continue
|
|
106
|
+
found.append(
|
|
107
|
+
ModelInfo(
|
|
108
|
+
id=model_id,
|
|
109
|
+
provider=self.name,
|
|
110
|
+
display_name=model.display_name,
|
|
111
|
+
capabilities=frozenset(_capabilities_of(model, model_id)),
|
|
112
|
+
context_window=model.input_token_limit,
|
|
113
|
+
max_output_tokens=model.output_token_limit,
|
|
114
|
+
raw=model.model_dump(mode="json"),
|
|
115
|
+
)
|
|
116
|
+
)
|
|
117
|
+
return found
|
|
118
|
+
|
|
119
|
+
def chat_model(self, model_id: str, **kwargs: Any) -> BaseChatModel:
|
|
120
|
+
return ChatGoogleGenerativeAI(
|
|
121
|
+
model=model_id, google_api_key=self._api_key, **kwargs
|
|
122
|
+
)
|