docketeer-deepinfra 0.0.14__tar.gz
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.
- docketeer_deepinfra-0.0.14/.gitignore +12 -0
- docketeer_deepinfra-0.0.14/PKG-INFO +61 -0
- docketeer_deepinfra-0.0.14/README.md +43 -0
- docketeer_deepinfra-0.0.14/pyproject.toml +62 -0
- docketeer_deepinfra-0.0.14/src/docketeer_deepinfra/__init__.py +55 -0
- docketeer_deepinfra-0.0.14/src/docketeer_deepinfra/api_backend.py +124 -0
- docketeer_deepinfra-0.0.14/src/docketeer_deepinfra/loop.py +410 -0
- docketeer_deepinfra-0.0.14/tests/test_api_backend.py +298 -0
- docketeer_deepinfra-0.0.14/tests/test_init.py +50 -0
- docketeer_deepinfra-0.0.14/tests/test_loop_agentic.py +296 -0
- docketeer_deepinfra-0.0.14/tests/test_loop_build.py +45 -0
- docketeer_deepinfra-0.0.14/tests/test_loop_callbacks.py +94 -0
- docketeer_deepinfra-0.0.14/tests/test_loop_execute.py +75 -0
- docketeer_deepinfra-0.0.14/tests/test_loop_serialize.py +110 -0
- docketeer_deepinfra-0.0.14/tests/test_loop_stream.py +481 -0
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: docketeer-deepinfra
|
|
3
|
+
Version: 0.0.14
|
|
4
|
+
Summary: DeepInfra inference backend plugin for Docketeer
|
|
5
|
+
Project-URL: Homepage, https://github.com/chrisguidry/docketeer
|
|
6
|
+
Project-URL: Repository, https://github.com/chrisguidry/docketeer
|
|
7
|
+
Project-URL: Issues, https://github.com/chrisguidry/docketeer/issues
|
|
8
|
+
Author-email: Chris Guidry <guid@omg.lol>
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
14
|
+
Requires-Python: >=3.12
|
|
15
|
+
Requires-Dist: docketeer
|
|
16
|
+
Requires-Dist: openai
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
|
|
19
|
+
# docketeer-deepinfra
|
|
20
|
+
|
|
21
|
+
DeepInfra inference backend plugin for Docketeer.
|
|
22
|
+
|
|
23
|
+
This plugin provides inference through the DeepInfra native API.
|
|
24
|
+
|
|
25
|
+
## Installation
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
pip install docketeer-deepinfra
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Configuration
|
|
32
|
+
|
|
33
|
+
Configure the DeepInfra backend with environment variables:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
# Required: Your DeepInfra API key
|
|
37
|
+
export DOCKETEER_DEEPINFRA_API_KEY=your-api-key-here
|
|
38
|
+
|
|
39
|
+
# Optional: Override the API base URL (defaults to https://api.deepinfra.com)
|
|
40
|
+
export DOCKETEER_DEEPINFRA_BASE_URL=https://api.deepinfra.com
|
|
41
|
+
|
|
42
|
+
# Optional: Set the default model (defaults to meta-llama/Llama-3.3-70B-Instruct)
|
|
43
|
+
export DOCKETEER_DEEPINFRA_MODEL=meta-llama/Llama-3.3-70B-Instruct
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Then configure Docketeer to use the DeepInfra inference plugin:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
export DOCKETEER_INFERENCE=deepinfra
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Supported Models
|
|
53
|
+
|
|
54
|
+
Any model available on DeepInfra can be used. Common models include:
|
|
55
|
+
|
|
56
|
+
- `meta-llama/Llama-3.3-70B-Instruct` (default)
|
|
57
|
+
- `meta-llama/Llama-3.1-405B-Instruct`
|
|
58
|
+
- `Qwen/Qwen2.5-72B-Instruct`
|
|
59
|
+
- `deepseek-ai/DeepSeek-V3`
|
|
60
|
+
|
|
61
|
+
Set the model using `DOCKETEER_DEEPINFRA_MODEL` or by specifying the model in your Docketeer configuration.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# docketeer-deepinfra
|
|
2
|
+
|
|
3
|
+
DeepInfra inference backend plugin for Docketeer.
|
|
4
|
+
|
|
5
|
+
This plugin provides inference through the DeepInfra native API.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pip install docketeer-deepinfra
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Configuration
|
|
14
|
+
|
|
15
|
+
Configure the DeepInfra backend with environment variables:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
# Required: Your DeepInfra API key
|
|
19
|
+
export DOCKETEER_DEEPINFRA_API_KEY=your-api-key-here
|
|
20
|
+
|
|
21
|
+
# Optional: Override the API base URL (defaults to https://api.deepinfra.com)
|
|
22
|
+
export DOCKETEER_DEEPINFRA_BASE_URL=https://api.deepinfra.com
|
|
23
|
+
|
|
24
|
+
# Optional: Set the default model (defaults to meta-llama/Llama-3.3-70B-Instruct)
|
|
25
|
+
export DOCKETEER_DEEPINFRA_MODEL=meta-llama/Llama-3.3-70B-Instruct
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Then configure Docketeer to use the DeepInfra inference plugin:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
export DOCKETEER_INFERENCE=deepinfra
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Supported Models
|
|
35
|
+
|
|
36
|
+
Any model available on DeepInfra can be used. Common models include:
|
|
37
|
+
|
|
38
|
+
- `meta-llama/Llama-3.3-70B-Instruct` (default)
|
|
39
|
+
- `meta-llama/Llama-3.1-405B-Instruct`
|
|
40
|
+
- `Qwen/Qwen2.5-72B-Instruct`
|
|
41
|
+
- `deepseek-ai/DeepSeek-V3`
|
|
42
|
+
|
|
43
|
+
Set the model using `DOCKETEER_DEEPINFRA_MODEL` or by specifying the model in your Docketeer configuration.
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "docketeer-deepinfra"
|
|
3
|
+
dynamic = ["version"]
|
|
4
|
+
description = "DeepInfra inference backend plugin for Docketeer"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
authors = [
|
|
7
|
+
{ name = "Chris Guidry", email = "guid@omg.lol" }
|
|
8
|
+
]
|
|
9
|
+
license = "MIT"
|
|
10
|
+
requires-python = ">=3.12"
|
|
11
|
+
classifiers = [
|
|
12
|
+
"Development Status :: 3 - Alpha",
|
|
13
|
+
"Programming Language :: Python :: 3",
|
|
14
|
+
"License :: OSI Approved :: MIT License",
|
|
15
|
+
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
|
16
|
+
]
|
|
17
|
+
dependencies = [
|
|
18
|
+
"openai",
|
|
19
|
+
"docketeer",
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
[project.urls]
|
|
23
|
+
Homepage = "https://github.com/chrisguidry/docketeer"
|
|
24
|
+
Repository = "https://github.com/chrisguidry/docketeer"
|
|
25
|
+
Issues = "https://github.com/chrisguidry/docketeer/issues"
|
|
26
|
+
|
|
27
|
+
[project.entry-points."docketeer.inference"]
|
|
28
|
+
deepinfra = "docketeer_deepinfra:create_backend"
|
|
29
|
+
|
|
30
|
+
[build-system]
|
|
31
|
+
requires = ["hatchling", "hatch-vcs"]
|
|
32
|
+
build-backend = "hatchling.build"
|
|
33
|
+
|
|
34
|
+
[tool.hatch.version]
|
|
35
|
+
source = "vcs"
|
|
36
|
+
raw-options.root = ".."
|
|
37
|
+
|
|
38
|
+
[tool.hatch.build.targets.wheel]
|
|
39
|
+
packages = ["src/docketeer_deepinfra"]
|
|
40
|
+
|
|
41
|
+
[tool.uv.sources]
|
|
42
|
+
docketeer = { workspace = true }
|
|
43
|
+
|
|
44
|
+
[tool.pytest_env]
|
|
45
|
+
DOCKETEER_DEEPINFRA_API_KEY = "test-key"
|
|
46
|
+
DOCKETEER_DEEPINFRA_BASE_URL = "https://api.deepinfra.com/v1"
|
|
47
|
+
|
|
48
|
+
[tool.pytest.ini_options]
|
|
49
|
+
minversion = "9.0"
|
|
50
|
+
timeout = 1
|
|
51
|
+
addopts = [
|
|
52
|
+
"--import-mode=importlib",
|
|
53
|
+
"--cov=docketeer_deepinfra",
|
|
54
|
+
"--cov=tests",
|
|
55
|
+
"--cov-branch",
|
|
56
|
+
"--cov-report=term-missing",
|
|
57
|
+
"--cov-fail-under=100",
|
|
58
|
+
]
|
|
59
|
+
asyncio_mode = "auto"
|
|
60
|
+
filterwarnings = [
|
|
61
|
+
"error",
|
|
62
|
+
]
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"""DeepInfra inference backend plugin for Docketeer."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import logging
|
|
6
|
+
from typing import TYPE_CHECKING
|
|
7
|
+
|
|
8
|
+
from docketeer import environment
|
|
9
|
+
from docketeer.executor import CommandExecutor
|
|
10
|
+
|
|
11
|
+
if TYPE_CHECKING:
|
|
12
|
+
from docketeer.brain.backend import InferenceBackend
|
|
13
|
+
|
|
14
|
+
log = logging.getLogger(__name__)
|
|
15
|
+
|
|
16
|
+
DEFAULT_MODEL = "MiniMaxAI/MiniMax-M2.5"
|
|
17
|
+
|
|
18
|
+
# Tier to max tokens mapping
|
|
19
|
+
TIER_MAX_TOKENS = {
|
|
20
|
+
"smart": 128_000,
|
|
21
|
+
"balanced": 64_000,
|
|
22
|
+
"fast": 16_000,
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def create_backend(executor: CommandExecutor | None) -> InferenceBackend:
|
|
27
|
+
"""Factory function to create a DeepInfra backend.
|
|
28
|
+
|
|
29
|
+
This function is the entry point for the docketeer.inference plugin.
|
|
30
|
+
It creates a DeepInfra API backend.
|
|
31
|
+
|
|
32
|
+
Configuration (environment variables):
|
|
33
|
+
DEEPINFRA_API_KEY: Required. Your DeepInfra API key.
|
|
34
|
+
DEEPINFRA_BASE_URL: Optional. Defaults to https://api.deepinfra.com/v1/openai
|
|
35
|
+
DEEPINFRA_MODEL: Optional. Default model ID. Defaults to MiniMaxAI/MiniMax-M2.5
|
|
36
|
+
|
|
37
|
+
Args:
|
|
38
|
+
executor: CommandExecutor instance (unused for API backend)
|
|
39
|
+
|
|
40
|
+
Returns:
|
|
41
|
+
An InferenceBackend implementation
|
|
42
|
+
|
|
43
|
+
Raises:
|
|
44
|
+
KeyError: If API key is not configured
|
|
45
|
+
"""
|
|
46
|
+
from docketeer_deepinfra.api_backend import DeepInfraAPIBackend
|
|
47
|
+
|
|
48
|
+
api_key = environment.get_str("DEEPINFRA_API_KEY")
|
|
49
|
+
base_url = environment.get_str(
|
|
50
|
+
"DEEPINFRA_BASE_URL", "https://api.deepinfra.com/v1/openai"
|
|
51
|
+
)
|
|
52
|
+
default_model = environment.get_str("DEEPINFRA_MODEL", DEFAULT_MODEL)
|
|
53
|
+
return DeepInfraAPIBackend(
|
|
54
|
+
api_key=api_key, base_url=base_url, default_model=default_model
|
|
55
|
+
)
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"""DeepInfraAPIBackend: InferenceBackend backed by DeepInfra via OpenAI SDK."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import logging
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from typing import TYPE_CHECKING
|
|
9
|
+
|
|
10
|
+
from openai import APIError, AsyncOpenAI, AuthenticationError, RateLimitError
|
|
11
|
+
|
|
12
|
+
from docketeer import environment
|
|
13
|
+
from docketeer.brain.backend import (
|
|
14
|
+
BackendAuthError,
|
|
15
|
+
BackendError,
|
|
16
|
+
ContextTooLargeError,
|
|
17
|
+
InferenceBackend,
|
|
18
|
+
)
|
|
19
|
+
from docketeer.brain.core import InferenceModel
|
|
20
|
+
from docketeer_deepinfra import TIER_MAX_TOKENS
|
|
21
|
+
from docketeer_deepinfra.loop import _serialize_messages, agentic_loop
|
|
22
|
+
|
|
23
|
+
if TYPE_CHECKING:
|
|
24
|
+
from docketeer.brain.core import ProcessCallbacks
|
|
25
|
+
from docketeer.prompt import MessageParam, SystemBlock
|
|
26
|
+
from docketeer.tools import ToolContext, ToolDefinition
|
|
27
|
+
|
|
28
|
+
log = logging.getLogger(__name__)
|
|
29
|
+
|
|
30
|
+
DEFAULT_MODEL = "MiniMaxAI/MiniMax-M2.5"
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class DeepInfraAPIBackend(InferenceBackend):
|
|
34
|
+
def __init__(
|
|
35
|
+
self,
|
|
36
|
+
api_key: str,
|
|
37
|
+
base_url: str = "https://api.deepinfra.com/v1",
|
|
38
|
+
default_model: str = DEFAULT_MODEL,
|
|
39
|
+
) -> None:
|
|
40
|
+
self._api_key = api_key
|
|
41
|
+
self._base_url = base_url.rstrip("/")
|
|
42
|
+
self._default_model = default_model
|
|
43
|
+
self._client = AsyncOpenAI(
|
|
44
|
+
base_url=self._base_url,
|
|
45
|
+
api_key=api_key,
|
|
46
|
+
max_retries=0,
|
|
47
|
+
timeout=300.0,
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
async def __aexit__(self, *exc: object) -> None:
|
|
51
|
+
await self._client.close()
|
|
52
|
+
|
|
53
|
+
async def run_agentic_loop(
|
|
54
|
+
self,
|
|
55
|
+
tier: str,
|
|
56
|
+
system: list[SystemBlock],
|
|
57
|
+
messages: list[MessageParam],
|
|
58
|
+
tools: list[ToolDefinition],
|
|
59
|
+
tool_context: ToolContext,
|
|
60
|
+
audit_path: Path,
|
|
61
|
+
usage_path: Path,
|
|
62
|
+
callbacks: ProcessCallbacks | None,
|
|
63
|
+
*,
|
|
64
|
+
thinking: bool = False,
|
|
65
|
+
) -> str:
|
|
66
|
+
# Resolve tier to InferenceModel using environment variables
|
|
67
|
+
model_id = environment.get_str(
|
|
68
|
+
f"DEEPINFRA_MODEL_{tier.upper()}", self._default_model
|
|
69
|
+
)
|
|
70
|
+
max_tokens = TIER_MAX_TOKENS.get(tier, 64_000)
|
|
71
|
+
model = InferenceModel(model_id=model_id, max_output_tokens=max_tokens)
|
|
72
|
+
|
|
73
|
+
try:
|
|
74
|
+
return await agentic_loop(
|
|
75
|
+
self._client,
|
|
76
|
+
model,
|
|
77
|
+
system,
|
|
78
|
+
messages,
|
|
79
|
+
tools,
|
|
80
|
+
tool_context,
|
|
81
|
+
audit_path,
|
|
82
|
+
usage_path,
|
|
83
|
+
callbacks.on_first_text if callbacks else None,
|
|
84
|
+
callbacks.on_text if callbacks else None,
|
|
85
|
+
callbacks.on_tool_start if callbacks else None,
|
|
86
|
+
callbacks.on_tool_end if callbacks else None,
|
|
87
|
+
callbacks.interrupted if callbacks else None,
|
|
88
|
+
default_model=self._default_model,
|
|
89
|
+
)
|
|
90
|
+
except RateLimitError as exc:
|
|
91
|
+
raise BackendAuthError(str(exc)) from exc
|
|
92
|
+
except AuthenticationError as exc:
|
|
93
|
+
raise BackendAuthError(str(exc)) from exc
|
|
94
|
+
except APIError as exc:
|
|
95
|
+
msg = str(exc).lower()
|
|
96
|
+
if "413" in msg or "payload too large" in msg or "context length" in msg:
|
|
97
|
+
raise ContextTooLargeError(str(exc)) from exc
|
|
98
|
+
raise BackendError(str(exc)) from exc
|
|
99
|
+
|
|
100
|
+
async def count_tokens(
|
|
101
|
+
self,
|
|
102
|
+
model_id: str,
|
|
103
|
+
system: list[SystemBlock],
|
|
104
|
+
tools: list[ToolDefinition],
|
|
105
|
+
messages: list[MessageParam],
|
|
106
|
+
) -> int:
|
|
107
|
+
serialized = _serialize_messages(system, messages)
|
|
108
|
+
return len(json.dumps(serialized)) // 4
|
|
109
|
+
|
|
110
|
+
async def utility_complete(
|
|
111
|
+
self,
|
|
112
|
+
prompt: str,
|
|
113
|
+
*,
|
|
114
|
+
max_tokens: int = 1024,
|
|
115
|
+
) -> str:
|
|
116
|
+
try:
|
|
117
|
+
response = await self._client.chat.completions.create(
|
|
118
|
+
model=self._default_model,
|
|
119
|
+
messages=[{"role": "user", "content": prompt}],
|
|
120
|
+
max_tokens=max_tokens,
|
|
121
|
+
)
|
|
122
|
+
return response.choices[0].message.content or ""
|
|
123
|
+
except APIError as exc:
|
|
124
|
+
raise BackendError(str(exc)) from exc
|