solwyn-cli 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.
solwyn_cli/__init__.py ADDED
@@ -0,0 +1,3 @@
1
+ """Solwyn CLI package."""
2
+
3
+ __version__ = "0.1.0"
@@ -0,0 +1 @@
1
+ """Small, public-contract mirrors used by the standalone CLI."""
@@ -0,0 +1,21 @@
1
+ """Structural validation for project API keys.
2
+
3
+ This module intentionally mirrors only the public key shape. Authentication
4
+ remains the API's responsibility.
5
+ """
6
+
7
+ import re
8
+ from typing import Final
9
+
10
+ PROJECT_KEY_PATTERN: Final = re.compile(r"^sk_proj_[a-f0-9]{64}$")
11
+
12
+
13
+ def validate_project_key_format(project_key: str) -> str:
14
+ """Return a structurally valid project API key without authenticating it.
15
+
16
+ Invalid values are never interpolated into the exception so credential
17
+ material cannot leak through user-facing output or logs.
18
+ """
19
+ if PROJECT_KEY_PATTERN.fullmatch(project_key) is None:
20
+ raise ValueError("Invalid project key format")
21
+ return project_key
@@ -0,0 +1,185 @@
1
+ """Pydantic v2 mirrors of the request bodies constructed by the CLI."""
2
+
3
+ from datetime import datetime
4
+ from enum import StrEnum
5
+ from typing import Annotated, Literal
6
+
7
+ from pydantic import BaseModel, ConfigDict, Field, SecretStr, field_serializer
8
+
9
+
10
+ class _WireModel(BaseModel):
11
+ model_config = ConfigDict(extra="forbid")
12
+
13
+
14
+ class ProviderName(StrEnum):
15
+ """Provider identifiers accepted by budget request endpoints."""
16
+
17
+ OPENAI = "openai"
18
+ ANTHROPIC = "anthropic"
19
+ GOOGLE = "google"
20
+ BEDROCK = "bedrock"
21
+ XAI = "xai"
22
+ DEEPSEEK = "deepseek"
23
+ MISTRAL = "mistral"
24
+ QWEN = "qwen"
25
+ GROQ = "groq"
26
+ TOGETHER = "together"
27
+ FIREWORKS = "fireworks"
28
+ PERPLEXITY = "perplexity"
29
+ AZURE_OPENAI = "azure_openai"
30
+ OPENROUTER = "openrouter"
31
+ ZAI = "zai"
32
+ OLLAMA = "ollama"
33
+ VLLM = "vllm"
34
+ LMSTUDIO = "lmstudio"
35
+ OPENAI_COMPATIBLE = "openai_compatible"
36
+
37
+
38
+ class ServiceTier(StrEnum):
39
+ """Provider service tiers accepted by budget confirmation."""
40
+
41
+ AUTO = "auto"
42
+ DEFAULT = "default"
43
+ FLEX = "flex"
44
+ SCALE = "scale"
45
+ PRIORITY = "priority"
46
+ STANDARD = "standard"
47
+ OPTIMIZED = "optimized"
48
+
49
+
50
+ class BudgetPeriod(StrEnum):
51
+ """Rolling window for budget accounting."""
52
+
53
+ DAILY = "daily"
54
+ WEEKLY = "weekly"
55
+ MONTHLY = "monthly"
56
+
57
+
58
+ class BudgetMode(StrEnum):
59
+ """Budget enforcement mode."""
60
+
61
+ ALERT_ONLY = "alert_only"
62
+ HARD_DENY = "hard_deny"
63
+
64
+
65
+ class _ThresholdConfig(_WireModel):
66
+ type: Literal["budget_threshold"] = "budget_threshold"
67
+ percent: Annotated[int, Field(ge=1, le=100)]
68
+ channel_ids: list[str] = Field(default_factory=list)
69
+ snoozed_until: datetime | None = None
70
+ paused: bool = False
71
+
72
+
73
+ class _ForecastOverrunConfig(_WireModel):
74
+ type: Literal["forecast_overrun"]
75
+ spend_threshold_usd: Annotated[float, Field(gt=0)]
76
+ period: Literal["month"] = "month"
77
+ channel_ids: list[str] = Field(default_factory=list)
78
+ snoozed_until: datetime | None = None
79
+ paused: bool = False
80
+
81
+
82
+ class _DailyAnomalyConfig(_WireModel):
83
+ type: Literal["daily_anomaly"]
84
+ multiplier: Annotated[float, Field(gt=1, le=100)]
85
+ lookback_days: Annotated[int, Field(ge=3, le=30)] = 7
86
+ channel_ids: list[str] = Field(default_factory=list)
87
+ snoozed_until: datetime | None = None
88
+ paused: bool = False
89
+
90
+
91
+ class _UnitCostAnomalyConfig(_WireModel):
92
+ type: Literal["unit_cost_anomaly"]
93
+ multiplier: Annotated[float, Field(gt=1, le=100)]
94
+ lookback_days: Annotated[int, Field(ge=3, le=30)] = 7
95
+ channel_ids: list[str] = Field(default_factory=list)
96
+ snoozed_until: datetime | None = None
97
+ paused: bool = False
98
+
99
+
100
+ _BudgetRule = (
101
+ _ThresholdConfig
102
+ | _ForecastOverrunConfig
103
+ | _DailyAnomalyConfig
104
+ | _UnitCostAnomalyConfig
105
+ )
106
+
107
+
108
+ class TokenDetails(_WireModel):
109
+ """Normalized provider token usage used to settle a reservation."""
110
+
111
+ input_tokens: Annotated[int, Field(ge=0, le=100_000_000)] = 0
112
+ output_tokens: Annotated[int, Field(ge=0, le=100_000_000)] = 0
113
+ cached_input_tokens: Annotated[int, Field(ge=0, le=100_000_000)] = 0
114
+ cache_creation_5m_tokens: Annotated[int, Field(ge=0, le=100_000_000)] = 0
115
+ cache_creation_1h_tokens: Annotated[int, Field(ge=0, le=100_000_000)] = 0
116
+ reasoning_tokens: Annotated[int, Field(ge=0, le=100_000_000)] = 0
117
+ audio_input_tokens: Annotated[int, Field(ge=0, le=100_000_000)] = 0
118
+ audio_output_tokens: Annotated[int, Field(ge=0, le=100_000_000)] = 0
119
+ accepted_prediction_tokens: Annotated[int, Field(ge=0, le=100_000_000)] = 0
120
+ rejected_prediction_tokens: Annotated[int, Field(ge=0, le=100_000_000)] = 0
121
+ tool_use_input_tokens: Annotated[int, Field(ge=0, le=100_000_000)] = 0
122
+ is_estimated: bool = False
123
+
124
+
125
+ class LoginRequest(_WireModel):
126
+ model_config = ConfigDict(extra="forbid", hide_input_in_errors=True)
127
+
128
+ email: str
129
+ password: Annotated[SecretStr, Field(max_length=128)]
130
+ plan: Literal["founder", "team", "scale"] | None = None
131
+ billing_interval: Literal["month", "year"] | None = None
132
+
133
+ @field_serializer("password")
134
+ def serialize_password(self, value: SecretStr) -> str:
135
+ """Reveal the password only while constructing the login wire body."""
136
+ return value.get_secret_value()
137
+
138
+
139
+ class RefreshRequest(_WireModel):
140
+ refresh_token: str
141
+
142
+
143
+ class ProjectCreateRequest(_WireModel):
144
+ name: Annotated[str, Field(min_length=1, max_length=100)]
145
+ budget_limit: Annotated[float, Field(gt=0)] = 100.0
146
+ budget_period: Annotated[str, Field(pattern=r"^(daily|weekly|monthly)$")] = (
147
+ "monthly"
148
+ )
149
+ budget_mode: Annotated[str, Field(pattern=r"^(alert_only|hard_deny)$")] = (
150
+ "alert_only"
151
+ )
152
+
153
+
154
+ class ProjectKeyRotateRequest(_WireModel):
155
+ grace_seconds: Annotated[int, Field(ge=0, le=604800)] | None = None
156
+
157
+
158
+ class BudgetUpdateRequest(_WireModel):
159
+ limit_usd: Annotated[float, Field(gt=0)]
160
+ period: BudgetPeriod
161
+ mode: BudgetMode
162
+ sub_period: BudgetPeriod | None = None
163
+ sub_limit_usd: float | None = None
164
+ thresholds: Annotated[list[_BudgetRule], Field(max_length=50)]
165
+
166
+
167
+ class BudgetCheckRequest(_WireModel):
168
+ estimated_input_tokens: Annotated[int, Field(ge=0)]
169
+ model: Annotated[str, Field(max_length=2048)]
170
+ provider: ProviderName
171
+ fallback_providers: list[ProviderName] = Field(default_factory=list)
172
+ fallback_models: Annotated[
173
+ list[Annotated[str, Field(max_length=2048)]], Field(max_length=8)
174
+ ] = Field(default_factory=list)
175
+
176
+
177
+ class BudgetConfirmRequest(_WireModel):
178
+ reservation_id: str
179
+ model: Annotated[str, Field(max_length=2048)]
180
+ provider: ProviderName
181
+ is_provider_fallback: bool = False
182
+ call_id: Annotated[str, Field(max_length=36)]
183
+ token_details: TokenDetails
184
+ provider_region: Annotated[str, Field(max_length=32)] | None = None
185
+ service_tier: ServiceTier | None = None