studiorelay 0.3.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.
- kimibridge/__init__.py +1 -0
- kimibridge/cli.py +461 -0
- kimibridge/compatibility/__init__.py +25 -0
- kimibridge/compatibility/errors.py +62 -0
- kimibridge/compatibility/model_aliases.py +44 -0
- kimibridge/compatibility/models.py +69 -0
- kimibridge/compatibility/parameters.py +29 -0
- kimibridge/compatibility/pipeline.py +42 -0
- kimibridge/compatibility/profiles.py +138 -0
- kimibridge/compatibility/responses.py +766 -0
- kimibridge/compatibility/roles.py +33 -0
- kimibridge/config.py +195 -0
- kimibridge/health.py +51 -0
- kimibridge/ports.py +255 -0
- kimibridge/server.py +309 -0
- kimibridge/service.py +182 -0
- kimibridge/upstream.py +168 -0
- studiorelay/__init__.py +1 -0
- studiorelay/cli.py +514 -0
- studiorelay/compatibility/__init__.py +25 -0
- studiorelay/compatibility/errors.py +62 -0
- studiorelay/compatibility/model_aliases.py +44 -0
- studiorelay/compatibility/models.py +69 -0
- studiorelay/compatibility/parameters.py +29 -0
- studiorelay/compatibility/pipeline.py +42 -0
- studiorelay/compatibility/profiles.py +138 -0
- studiorelay/compatibility/responses.py +766 -0
- studiorelay/compatibility/roles.py +33 -0
- studiorelay/config.py +326 -0
- studiorelay/health.py +53 -0
- studiorelay/ports.py +277 -0
- studiorelay/server.py +321 -0
- studiorelay/service.py +237 -0
- studiorelay/upstream.py +171 -0
- studiorelay-0.3.0.dist-info/METADATA +395 -0
- studiorelay-0.3.0.dist-info/RECORD +39 -0
- studiorelay-0.3.0.dist-info/WHEEL +5 -0
- studiorelay-0.3.0.dist-info/entry_points.txt +4 -0
- studiorelay-0.3.0.dist-info/top_level.txt +2 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from copy import deepcopy
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
from kimibridge.compatibility.profiles import KIMI_PROFILE, ProviderProfile
|
|
7
|
+
|
|
8
|
+
UNSUPPORTED_PARAMETERS = {
|
|
9
|
+
"metadata",
|
|
10
|
+
"parallel_tool_calls",
|
|
11
|
+
"store",
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def normalize_parameters(
|
|
16
|
+
payload: dict[str, Any],
|
|
17
|
+
mode: str = "compatible",
|
|
18
|
+
profile: ProviderProfile | None = None,
|
|
19
|
+
) -> dict[str, Any]:
|
|
20
|
+
if mode in {"passthrough", "strict"}:
|
|
21
|
+
return deepcopy(payload)
|
|
22
|
+
|
|
23
|
+
active_profile = profile or KIMI_PROFILE
|
|
24
|
+
keys_to_remove = active_profile.unsupported_parameters if active_profile else UNSUPPORTED_PARAMETERS
|
|
25
|
+
|
|
26
|
+
normalized = deepcopy(payload)
|
|
27
|
+
for key in keys_to_remove:
|
|
28
|
+
normalized.pop(key, None)
|
|
29
|
+
return normalized
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from kimibridge.compatibility.model_aliases import normalize_model_aliases
|
|
6
|
+
from kimibridge.compatibility.parameters import normalize_parameters
|
|
7
|
+
from kimibridge.compatibility.profiles import (
|
|
8
|
+
ProviderProfile,
|
|
9
|
+
detect_provider,
|
|
10
|
+
get_provider_profile,
|
|
11
|
+
)
|
|
12
|
+
from kimibridge.compatibility.roles import normalize_roles
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
VALID_MODES = {"compatible", "passthrough", "strict"}
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def normalize_request(
|
|
19
|
+
payload: dict[str, Any],
|
|
20
|
+
mode: str = "compatible",
|
|
21
|
+
provider: str | ProviderProfile | None = None,
|
|
22
|
+
base_url: str | None = None,
|
|
23
|
+
headers: dict[str, str] | None = None,
|
|
24
|
+
) -> dict[str, Any]:
|
|
25
|
+
if mode not in VALID_MODES:
|
|
26
|
+
raise ValueError(f"Unsupported compatibility mode: {mode}")
|
|
27
|
+
|
|
28
|
+
if isinstance(provider, ProviderProfile):
|
|
29
|
+
profile = provider
|
|
30
|
+
else:
|
|
31
|
+
profile = detect_provider(
|
|
32
|
+
model=payload.get("model") if isinstance(payload, dict) else None,
|
|
33
|
+
base_url=base_url,
|
|
34
|
+
configured_provider=provider,
|
|
35
|
+
headers=headers,
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
normalized = normalize_roles(payload, mode=mode, profile=profile)
|
|
39
|
+
normalized = normalize_parameters(normalized, mode=mode, profile=profile)
|
|
40
|
+
if mode != "passthrough":
|
|
41
|
+
normalized = normalize_model_aliases(normalized, profile=profile)
|
|
42
|
+
return normalized
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@dataclass(frozen=True)
|
|
8
|
+
class ProviderProfile:
|
|
9
|
+
name: str
|
|
10
|
+
supports_developer_role: bool = False
|
|
11
|
+
developer_role_target: str = "system"
|
|
12
|
+
supported_roles: frozenset[str] = frozenset({"system", "user", "assistant", "tool"})
|
|
13
|
+
unsupported_parameters: frozenset[str] = frozenset()
|
|
14
|
+
default_base_url: str = ""
|
|
15
|
+
default_models: tuple[dict[str, Any], ...] = ()
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
KIMI_PROFILE = ProviderProfile(
|
|
19
|
+
name="kimi",
|
|
20
|
+
supports_developer_role=False,
|
|
21
|
+
developer_role_target="system",
|
|
22
|
+
supported_roles=frozenset({"system", "user", "assistant", "tool"}),
|
|
23
|
+
unsupported_parameters=frozenset({"metadata", "parallel_tool_calls", "store"}),
|
|
24
|
+
default_base_url="https://api.moonshot.ai",
|
|
25
|
+
default_models=(
|
|
26
|
+
{"id": "kimi-k3", "object": "model", "owned_by": "moonshot"},
|
|
27
|
+
{"id": "kimi-latest", "object": "model", "owned_by": "moonshot"},
|
|
28
|
+
{"id": "kimi-k1.5", "object": "model", "owned_by": "moonshot"},
|
|
29
|
+
{"id": "kimi-k2", "object": "model", "owned_by": "moonshot"},
|
|
30
|
+
{"id": "moonshot-v1-auto", "object": "model", "owned_by": "moonshot"},
|
|
31
|
+
{"id": "moonshot-v1-8k", "object": "model", "owned_by": "moonshot"},
|
|
32
|
+
{"id": "moonshot-v1-32k", "object": "model", "owned_by": "moonshot"},
|
|
33
|
+
{"id": "moonshot-v1-128k", "object": "model", "owned_by": "moonshot"},
|
|
34
|
+
{"id": "moonshot-v1-8k-vision-preview", "object": "model", "owned_by": "moonshot"},
|
|
35
|
+
{"id": "moonshot-v1-32k-vision-preview", "object": "model", "owned_by": "moonshot"},
|
|
36
|
+
{"id": "moonshot-v1-128k-vision-preview", "object": "model", "owned_by": "moonshot"},
|
|
37
|
+
),
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
DEEPSEEK_PROFILE = ProviderProfile(
|
|
41
|
+
name="deepseek",
|
|
42
|
+
supports_developer_role=False,
|
|
43
|
+
developer_role_target="system",
|
|
44
|
+
supported_roles=frozenset({"system", "user", "assistant", "tool", "latest_reminder"}),
|
|
45
|
+
unsupported_parameters=frozenset({"metadata", "store"}),
|
|
46
|
+
default_base_url="https://api.deepseek.com",
|
|
47
|
+
default_models=(
|
|
48
|
+
{"id": "deepseek-flash", "object": "model", "owned_by": "deepseek"},
|
|
49
|
+
{"id": "deepseek-v4-pro", "object": "model", "owned_by": "deepseek"},
|
|
50
|
+
{"id": "deepseek-chat", "object": "model", "owned_by": "deepseek"},
|
|
51
|
+
{"id": "deepseek-reasoner", "object": "model", "owned_by": "deepseek"},
|
|
52
|
+
{"id": "deepseek-v3", "object": "model", "owned_by": "deepseek"},
|
|
53
|
+
{"id": "deepseek-v3-pro", "object": "model", "owned_by": "deepseek"},
|
|
54
|
+
{"id": "deepseek-r1", "object": "model", "owned_by": "deepseek"},
|
|
55
|
+
{"id": "deepseek-coder", "object": "model", "owned_by": "deepseek"},
|
|
56
|
+
),
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
OPENAI_PROFILE = ProviderProfile(
|
|
60
|
+
name="openai",
|
|
61
|
+
supports_developer_role=True,
|
|
62
|
+
developer_role_target="developer",
|
|
63
|
+
supported_roles=frozenset({"system", "developer", "user", "assistant", "tool", "function"}),
|
|
64
|
+
unsupported_parameters=frozenset(),
|
|
65
|
+
default_base_url="https://api.openai.com",
|
|
66
|
+
default_models=(
|
|
67
|
+
{"id": "gpt-4o", "object": "model", "owned_by": "openai"},
|
|
68
|
+
{"id": "gpt-4o-mini", "object": "model", "owned_by": "openai"},
|
|
69
|
+
{"id": "o1", "object": "model", "owned_by": "openai"},
|
|
70
|
+
{"id": "o3-mini", "object": "model", "owned_by": "openai"},
|
|
71
|
+
),
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
GENERIC_PROFILE = ProviderProfile(
|
|
75
|
+
name="generic",
|
|
76
|
+
supports_developer_role=False,
|
|
77
|
+
developer_role_target="system",
|
|
78
|
+
supported_roles=frozenset({"system", "user", "assistant", "tool"}),
|
|
79
|
+
unsupported_parameters=frozenset({"metadata", "parallel_tool_calls", "store"}),
|
|
80
|
+
default_base_url="",
|
|
81
|
+
default_models=(
|
|
82
|
+
{"id": "default-model", "object": "model", "owned_by": "generic"},
|
|
83
|
+
),
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
PROFILES: dict[str, ProviderProfile] = {
|
|
87
|
+
"kimi": KIMI_PROFILE,
|
|
88
|
+
"moonshot": KIMI_PROFILE,
|
|
89
|
+
"deepseek": DEEPSEEK_PROFILE,
|
|
90
|
+
"openai": OPENAI_PROFILE,
|
|
91
|
+
"generic": GENERIC_PROFILE,
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def get_provider_profile(name_or_alias: str | None) -> ProviderProfile:
|
|
96
|
+
if not name_or_alias:
|
|
97
|
+
return KIMI_PROFILE
|
|
98
|
+
key = name_or_alias.strip().lower()
|
|
99
|
+
return PROFILES.get(key, GENERIC_PROFILE)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def detect_provider(
|
|
103
|
+
model: str | None = None,
|
|
104
|
+
base_url: str | None = None,
|
|
105
|
+
configured_provider: str | None = None,
|
|
106
|
+
headers: dict[str, str] | None = None,
|
|
107
|
+
) -> ProviderProfile:
|
|
108
|
+
"""
|
|
109
|
+
Detect provider profile based on explicit headers, upstream base URL heuristic,
|
|
110
|
+
model name heuristic, or configuration.
|
|
111
|
+
"""
|
|
112
|
+
if headers:
|
|
113
|
+
for k, v in headers.items():
|
|
114
|
+
if k.lower() in {"x-bridge-provider", "x-provider"}:
|
|
115
|
+
return get_provider_profile(v)
|
|
116
|
+
|
|
117
|
+
if model:
|
|
118
|
+
m = model.lower()
|
|
119
|
+
if "deepseek" in m:
|
|
120
|
+
return DEEPSEEK_PROFILE
|
|
121
|
+
if "kimi" in m or "moonshot" in m:
|
|
122
|
+
return KIMI_PROFILE
|
|
123
|
+
if m.startswith("gpt-") or m.startswith("o1") or m.startswith("o3"):
|
|
124
|
+
return OPENAI_PROFILE
|
|
125
|
+
|
|
126
|
+
if base_url:
|
|
127
|
+
u = base_url.lower()
|
|
128
|
+
if "deepseek.com" in u:
|
|
129
|
+
return DEEPSEEK_PROFILE
|
|
130
|
+
if "moonshot.ai" in u:
|
|
131
|
+
return KIMI_PROFILE
|
|
132
|
+
if "openai.com" in u:
|
|
133
|
+
return OPENAI_PROFILE
|
|
134
|
+
|
|
135
|
+
if configured_provider and configured_provider.lower() not in {"auto", "default", "all"}:
|
|
136
|
+
return get_provider_profile(configured_provider)
|
|
137
|
+
|
|
138
|
+
return KIMI_PROFILE
|