sofias-sdk-lite 0.1.5__tar.gz → 0.2.0__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.
Files changed (81) hide show
  1. sofias_sdk_lite-0.2.0/LICENSE +69 -0
  2. sofias_sdk_lite-0.1.5/README.md → sofias_sdk_lite-0.2.0/PKG-INFO +57 -10
  3. sofias_sdk_lite-0.1.5/PKG-INFO → sofias_sdk_lite-0.2.0/README.md +21 -28
  4. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/pyproject.toml +32 -2
  5. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/pyproject.toml.orig +24 -2
  6. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/__init__.py +2 -2
  7. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/config/agent_settings.py +2 -2
  8. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/llm/__init__.py +11 -11
  9. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/llm/factory.py +47 -34
  10. sofias_sdk_lite-0.1.5/src/sofias_sdk_lite/llm/bifrost.py → sofias_sdk_lite-0.2.0/src/sofias_sdk_lite/llm/gateway.py +53 -36
  11. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/llm/openai_compatible.py +2 -2
  12. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/llm/protocol.py +1 -1
  13. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/observability/__init__.py +1 -1
  14. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/observability/tracing.py +1 -1
  15. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/agent/__init__.py +0 -0
  16. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/agent/agent.py +0 -0
  17. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/agent/agent_builder.py +0 -0
  18. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/agent/agent_config.py +0 -0
  19. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/agent/execution_context.py +0 -0
  20. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/agent/middleware.py +0 -0
  21. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/agent/response_workflow.py +0 -0
  22. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/agent/streaming.py +0 -0
  23. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/config/__init__.py +0 -0
  24. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/config/defaults.py +0 -0
  25. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/config/runtime_config.py +0 -0
  26. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/config/sdk_config.py +0 -0
  27. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/config/source.py +0 -0
  28. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/contracts/__init__.py +0 -0
  29. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/contracts/agent_contracts.py +0 -0
  30. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/contracts/base_contracts.py +0 -0
  31. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/contracts/node_contracts.py +0 -0
  32. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/contracts/strict_contract.py +0 -0
  33. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/errors/__init__.py +0 -0
  34. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/errors/circuit_breaker.py +0 -0
  35. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/errors/error_handler.py +0 -0
  36. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/errors/exceptions.py +0 -0
  37. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/llm/tokens.py +0 -0
  38. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/llm/tools.py +0 -0
  39. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/messaging/__init__.py +0 -0
  40. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/messaging/models.py +0 -0
  41. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/nodes/__init__.py +0 -0
  42. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/nodes/aggregator_config.py +0 -0
  43. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/nodes/aggregator_node.py +0 -0
  44. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/nodes/base_node.py +0 -0
  45. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/nodes/delegation_config.py +0 -0
  46. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/nodes/delegation_node.py +0 -0
  47. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/nodes/delegation_transport.py +0 -0
  48. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/nodes/function_node.py +0 -0
  49. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/nodes/llm_node.py +0 -0
  50. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/nodes/llm_node_config.py +0 -0
  51. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/nodes/plan_executor.py +0 -0
  52. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/nodes/planner_node.py +0 -0
  53. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/nodes/planning_models.py +0 -0
  54. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/nodes/prompt_assembler.py +0 -0
  55. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/observability/_log.py +0 -0
  56. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/observability/events.py +0 -0
  57. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/observability/trace_context.py +0 -0
  58. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/py.typed +0 -0
  59. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/rabbitmq/__init__.py +0 -0
  60. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/rabbitmq/client.py +0 -0
  61. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/rabbitmq/config.py +0 -0
  62. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/rabbitmq/consumer.py +0 -0
  63. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/rabbitmq/delegation_transport.py +0 -0
  64. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/rabbitmq/publisher.py +0 -0
  65. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/rabbitmq/rpc_client.py +0 -0
  66. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/rabbitmq/types.py +0 -0
  67. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/routing/__init__.py +0 -0
  68. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/routing/router.py +0 -0
  69. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/routing/strategies.py +0 -0
  70. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/runner/__init__.py +0 -0
  71. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/runner/config.py +0 -0
  72. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/runner/runner.py +0 -0
  73. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/state/__init__.py +0 -0
  74. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/state/conversation_state.py +0 -0
  75. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/state/history.py +0 -0
  76. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/state/memory.py +0 -0
  77. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/tools.py +0 -0
  78. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/workflows/__init__.py +0 -0
  79. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/workflows/chat.py +0 -0
  80. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/workflows/null.py +0 -0
  81. {sofias_sdk_lite-0.1.5 → sofias_sdk_lite-0.2.0}/src/sofias_sdk_lite/workflows/streaming_chat.py +0 -0
@@ -0,0 +1,69 @@
1
+ Sofias SDK Lite License
2
+
3
+ Copyright (c) 2026 Sofias Tech, S.L. All rights reserved.
4
+
5
+ This licence applies to the software distributed as "sofias-sdk-lite" (the
6
+ "SDK"), including its source code, documentation and examples. By installing
7
+ or using the SDK you accept it. If you do not accept it, do not use the SDK.
8
+
9
+ 1. Permitted use
10
+
11
+ Sofias Tech, S.L. ("Sofias") grants you a free, non-exclusive,
12
+ non-transferable and revocable licence to download, install and use the SDK
13
+ solely to develop, test and run agents intended to run on the Sofias
14
+ platform, including its developer portal and marketplace.
15
+
16
+ 2. Source availability
17
+
18
+ The source code is made available so that you can read it and understand
19
+ how the SDK works. Access to the source code does not grant any right
20
+ beyond those set out in section 1.
21
+
22
+ 3. Restrictions
23
+
24
+ Except as expressly permitted in section 1, you may not:
25
+
26
+ a) use the SDK, or any part or derivative of it, to build, run or offer
27
+ agents, applications or services for any platform other than Sofias;
28
+ b) copy, modify, adapt, translate or create derivative works of the SDK,
29
+ other than the local copies needed for the permitted use;
30
+ c) distribute, publish, sublicense, sell, rent or otherwise make the SDK or
31
+ any derivative of it available to third parties;
32
+ d) remove or alter this notice or any other notice of ownership.
33
+
34
+ 4. Your agents
35
+
36
+ The agents you build with the SDK are yours. This licence does not give
37
+ Sofias any right over them. Any right Sofias needs to host, run or offer
38
+ your agents is governed by the terms you accept when you publish on the
39
+ Sofias platform.
40
+
41
+ 5. Termination
42
+
43
+ This licence ends automatically if you breach any of its terms. Sofias may
44
+ also revoke it by written notice. On termination you must stop using the SDK
45
+ and delete every copy in your possession.
46
+
47
+ 6. No warranty
48
+
49
+ THE SDK IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
50
+ IMPLIED, INCLUDING WITHOUT LIMITATION THE WARRANTIES OF MERCHANTABILITY,
51
+ FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
52
+
53
+ 7. Limitation of liability
54
+
55
+ TO THE MAXIMUM EXTENT PERMITTED BY LAW, SOFIAS SHALL NOT BE LIABLE FOR ANY
56
+ DAMAGE ARISING FROM THE USE OF, OR THE INABILITY TO USE, THE SDK.
57
+
58
+ 8. Changes
59
+
60
+ Sofias may publish new versions of this licence. Each release of the SDK is
61
+ governed by the licence included with it.
62
+
63
+ 9. Governing law and jurisdiction
64
+
65
+ This licence is governed by Spanish law. Any dispute shall be submitted to
66
+ the courts of Donostia - San Sebastian (Gipuzkoa), Spain, unless mandatory
67
+ law provides otherwise.
68
+
69
+ Contact: support@sofias.ai
@@ -1,7 +1,45 @@
1
+ Metadata-Version: 2.4
2
+ Name: sofias-sdk-lite
3
+ Version: 0.2.0
4
+ Summary: Build agents on the Sofias agent graph and run them over RabbitMQ.
5
+ Keywords: agents,ai,llm,rabbitmq,sofias
6
+ Author: Sofias Tech, S.L.
7
+ Author-email: Sofias Tech, S.L. <support@sofias.ai>
8
+ License-Expression: LicenseRef-Sofias-SDK-Lite
9
+ License-File: LICENSE
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Operating System :: OS Independent
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Topic :: Software Development :: Libraries
18
+ Classifier: Typing :: Typed
19
+ Requires-Dist: pydantic>=2.0
20
+ Requires-Dist: aio-pika>=9.0.0
21
+ Requires-Dist: rstream>=1.0.0
22
+ Requires-Dist: nh3>=0.3.6
23
+ Requires-Dist: httpx>=0.27.0
24
+ Requires-Dist: mkdocs>=1.6,<2 ; extra == 'docs'
25
+ Requires-Dist: mkdocs-material>=9.5 ; extra == 'docs'
26
+ Requires-Dist: mkdocstrings[python]>=0.25 ; extra == 'docs'
27
+ Requires-Dist: opentelemetry-api>=1.20.0 ; extra == 'otel'
28
+ Requires-Python: >=3.11
29
+ Project-URL: Homepage, https://sofias.ai/
30
+ Project-URL: Documentation, https://docs.sofias.ai/
31
+ Project-URL: Repository, https://github.com/Sofias-ai/sofias-sdk-lite
32
+ Project-URL: Changelog, https://github.com/Sofias-ai/sofias-sdk-lite/blob/main/CHANGELOG.md
33
+ Provides-Extra: docs
34
+ Provides-Extra: otel
35
+ Description-Content-Type: text/markdown
36
+
1
37
  # sofias-sdk-lite
2
38
 
3
39
  Build multi-node agents on a declarative graph and run them against RabbitMQ.
4
40
 
41
+ **Documentation:** [docs.sofias.ai](https://docs.sofias.ai/) · **Developer portal:** [developers.sofias.ai](https://developers.sofias.ai/) · **Source:** [github.com/Sofias-ai/sofias-sdk-lite](https://github.com/Sofias-ai/sofias-sdk-lite)
42
+
5
43
  `sofias-sdk-lite` gives you:
6
44
 
7
45
  - **An agent graph** — LLM nodes, function nodes, delegation nodes (agent-to-agent),
@@ -13,8 +51,8 @@ Build multi-node agents on a declarative graph and run them against RabbitMQ.
13
51
  - **A runner** — `AgentRunner` consumes tasks from a queue, resolves per-request
14
52
  settings, executes your agent, and streams the response back — with graceful
15
53
  shutdown, retries, and circuit breakers built in.
16
- - **An LLM that is already wired** — LLM nodes talk to the Sofias Bifrost
17
- gateway (or any OpenAI-compatible endpoint) using the model, URL and key
54
+ - **An LLM that is already wired** — LLM nodes talk to the Sofias gateway
55
+ (or any OpenAI-compatible endpoint) using the model, URL and key
18
56
  from the agent's settings or the `SOFIAS_LLM_*` environment. `create_llm()`
19
57
  builds the client when you need it explicitly; `LLMCallable` stays a protocol
20
58
  for anything the bundled clients do not cover.
@@ -97,12 +135,11 @@ resolved at `build()`:
97
135
 
98
136
  1. Under `AgentRunner`, from the per-task settings the platform sends
99
137
  (`model_name`, `router_url`, `router_api_key` on `BaseAgentSettings`).
100
- 2. Otherwise from the environment: `SOFIAS_LLM_MODEL`, `SOFIAS_LLM_BASE_URL`
101
- (default `http://bifrost:8080/v1`), `SOFIAS_LLM_API_KEY`,
102
- `SOFIAS_LLM_PROVIDER` (default `bifrost`). The `BIFROST_MODEL` /
103
- `BIFROST_BASE_URL` / `BIFROST_API_KEY` variables the Sofias Developer
104
- Portal injects into agent containers are accepted as fallbacks, so a
105
- portal-deployed agent needs no LLM configuration at all.
138
+ 2. Otherwise from the environment: `SOFIAS_LLM_MODEL`, `SOFIAS_LLM_BASE_URL`,
139
+ `SOFIAS_LLM_API_KEY` and `SOFIAS_LLM_PROVIDER` (default `sofias`). The
140
+ Sofias platform injects them into every agent it runs, so an agent
141
+ deployed through the developer portal needs no LLM configuration at all.
142
+ There is no default URL: to run locally against a real gateway, set it.
106
143
  3. Or explicitly: `.with_llm(create_llm(model="default", api_key=...))`.
107
144
 
108
145
  ```python
@@ -173,11 +210,21 @@ if __name__ == "__main__":
173
210
  ## Scope (v1)
174
211
 
175
212
  Core agent graph, RabbitMQ messaging, the runner, and LLM clients for the
176
- Bifrost gateway / any OpenAI-compatible endpoint ship today. Memory and MCP
213
+ Sofias gateway / any OpenAI-compatible endpoint ship today. Memory and MCP
177
214
  tool discovery are intentionally out of scope for v1 — the SDK ships the
178
215
  relevant protocols (`MemoryProvider`, `ToolProvider`) so you can plug in
179
216
  your own, and these become optional extras in a later release.
180
217
 
218
+ ## Source and contributions
219
+
220
+ The public repository holds read-only release snapshots: each release of
221
+ `sofias-sdk-lite` appears there as a single commit. Development happens
222
+ elsewhere, so pull requests cannot be merged and we do not accept
223
+ contributions at the moment. For questions or to report a problem, write to
224
+ support@sofias.ai.
225
+
181
226
  ## License
182
227
 
183
- Apache-2.0. See [LICENSE](LICENSE).
228
+ Source-available under the [Sofias SDK Lite License](https://github.com/Sofias-ai/sofias-sdk-lite/blob/main/LICENSE):
229
+ you may use `sofias-sdk-lite` to develop, test and run agents for the Sofias
230
+ platform. The agents you build with it are yours.
@@ -1,25 +1,9 @@
1
- Metadata-Version: 2.4
2
- Name: sofias-sdk-lite
3
- Version: 0.1.5
4
- Summary: Build agents on the Sofias agent graph and run them over RabbitMQ.
5
- License-Expression: Apache-2.0
6
- Requires-Dist: pydantic>=2.0
7
- Requires-Dist: aio-pika>=9.0.0
8
- Requires-Dist: rstream>=1.0.0
9
- Requires-Dist: nh3>=0.3.6
10
- Requires-Dist: httpx>=0.27.0
11
- Requires-Dist: mkdocs-material>=9.5 ; extra == 'docs'
12
- Requires-Dist: mkdocstrings[python]>=0.25 ; extra == 'docs'
13
- Requires-Dist: opentelemetry-api>=1.20.0 ; extra == 'otel'
14
- Requires-Python: >=3.11
15
- Provides-Extra: docs
16
- Provides-Extra: otel
17
- Description-Content-Type: text/markdown
18
-
19
1
  # sofias-sdk-lite
20
2
 
21
3
  Build multi-node agents on a declarative graph and run them against RabbitMQ.
22
4
 
5
+ **Documentation:** [docs.sofias.ai](https://docs.sofias.ai/) · **Developer portal:** [developers.sofias.ai](https://developers.sofias.ai/) · **Source:** [github.com/Sofias-ai/sofias-sdk-lite](https://github.com/Sofias-ai/sofias-sdk-lite)
6
+
23
7
  `sofias-sdk-lite` gives you:
24
8
 
25
9
  - **An agent graph** — LLM nodes, function nodes, delegation nodes (agent-to-agent),
@@ -31,8 +15,8 @@ Build multi-node agents on a declarative graph and run them against RabbitMQ.
31
15
  - **A runner** — `AgentRunner` consumes tasks from a queue, resolves per-request
32
16
  settings, executes your agent, and streams the response back — with graceful
33
17
  shutdown, retries, and circuit breakers built in.
34
- - **An LLM that is already wired** — LLM nodes talk to the Sofias Bifrost
35
- gateway (or any OpenAI-compatible endpoint) using the model, URL and key
18
+ - **An LLM that is already wired** — LLM nodes talk to the Sofias gateway
19
+ (or any OpenAI-compatible endpoint) using the model, URL and key
36
20
  from the agent's settings or the `SOFIAS_LLM_*` environment. `create_llm()`
37
21
  builds the client when you need it explicitly; `LLMCallable` stays a protocol
38
22
  for anything the bundled clients do not cover.
@@ -115,12 +99,11 @@ resolved at `build()`:
115
99
 
116
100
  1. Under `AgentRunner`, from the per-task settings the platform sends
117
101
  (`model_name`, `router_url`, `router_api_key` on `BaseAgentSettings`).
118
- 2. Otherwise from the environment: `SOFIAS_LLM_MODEL`, `SOFIAS_LLM_BASE_URL`
119
- (default `http://bifrost:8080/v1`), `SOFIAS_LLM_API_KEY`,
120
- `SOFIAS_LLM_PROVIDER` (default `bifrost`). The `BIFROST_MODEL` /
121
- `BIFROST_BASE_URL` / `BIFROST_API_KEY` variables the Sofias Developer
122
- Portal injects into agent containers are accepted as fallbacks, so a
123
- portal-deployed agent needs no LLM configuration at all.
102
+ 2. Otherwise from the environment: `SOFIAS_LLM_MODEL`, `SOFIAS_LLM_BASE_URL`,
103
+ `SOFIAS_LLM_API_KEY` and `SOFIAS_LLM_PROVIDER` (default `sofias`). The
104
+ Sofias platform injects them into every agent it runs, so an agent
105
+ deployed through the developer portal needs no LLM configuration at all.
106
+ There is no default URL: to run locally against a real gateway, set it.
124
107
  3. Or explicitly: `.with_llm(create_llm(model="default", api_key=...))`.
125
108
 
126
109
  ```python
@@ -191,11 +174,21 @@ if __name__ == "__main__":
191
174
  ## Scope (v1)
192
175
 
193
176
  Core agent graph, RabbitMQ messaging, the runner, and LLM clients for the
194
- Bifrost gateway / any OpenAI-compatible endpoint ship today. Memory and MCP
177
+ Sofias gateway / any OpenAI-compatible endpoint ship today. Memory and MCP
195
178
  tool discovery are intentionally out of scope for v1 — the SDK ships the
196
179
  relevant protocols (`MemoryProvider`, `ToolProvider`) so you can plug in
197
180
  your own, and these become optional extras in a later release.
198
181
 
182
+ ## Source and contributions
183
+
184
+ The public repository holds read-only release snapshots: each release of
185
+ `sofias-sdk-lite` appears there as a single commit. Development happens
186
+ elsewhere, so pull requests cannot be merged and we do not accept
187
+ contributions at the moment. For questions or to report a problem, write to
188
+ support@sofias.ai.
189
+
199
190
  ## License
200
191
 
201
- Apache-2.0. See [LICENSE](LICENSE).
192
+ Source-available under the [Sofias SDK Lite License](https://github.com/Sofias-ai/sofias-sdk-lite/blob/main/LICENSE):
193
+ you may use `sofias-sdk-lite` to develop, test and run agents for the Sofias
194
+ platform. The agents you build with it are yours.
@@ -1,10 +1,29 @@
1
1
  [project]
2
2
  name = "sofias-sdk-lite"
3
- version = "0.1.5"
3
+ version = "0.2.0"
4
4
  description = "Build agents on the Sofias agent graph and run them over RabbitMQ."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
7
- license = "Apache-2.0"
7
+ license = "LicenseRef-Sofias-SDK-Lite"
8
+ license-files = ["LICENSE"]
9
+ keywords = [
10
+ "agents",
11
+ "ai",
12
+ "llm",
13
+ "rabbitmq",
14
+ "sofias",
15
+ ]
16
+ classifiers = [
17
+ "Development Status :: 3 - Alpha",
18
+ "Intended Audience :: Developers",
19
+ "Operating System :: OS Independent",
20
+ "Programming Language :: Python :: 3",
21
+ "Programming Language :: Python :: 3.11",
22
+ "Programming Language :: Python :: 3.12",
23
+ "Programming Language :: Python :: 3.13",
24
+ "Topic :: Software Development :: Libraries",
25
+ "Typing :: Typed",
26
+ ]
8
27
  dependencies = [
9
28
  "pydantic>=2.0",
10
29
  "aio-pika>=9.0.0",
@@ -13,9 +32,20 @@ dependencies = [
13
32
  "httpx>=0.27.0",
14
33
  ]
15
34
 
35
+ [[project.authors]]
36
+ name = "Sofias Tech, S.L."
37
+ email = "support@sofias.ai"
38
+
39
+ [project.urls]
40
+ Homepage = "https://sofias.ai/"
41
+ Documentation = "https://docs.sofias.ai/"
42
+ Repository = "https://github.com/Sofias-ai/sofias-sdk-lite"
43
+ Changelog = "https://github.com/Sofias-ai/sofias-sdk-lite/blob/main/CHANGELOG.md"
44
+
16
45
  [project.optional-dependencies]
17
46
  otel = ["opentelemetry-api>=1.20.0"]
18
47
  docs = [
48
+ "mkdocs>=1.6,<2",
19
49
  "mkdocs-material>=9.5",
20
50
  "mkdocstrings[python]>=0.25",
21
51
  ]
@@ -1,10 +1,24 @@
1
1
  [project]
2
2
  name = "sofias-sdk-lite"
3
- version = "0.1.5"
3
+ version = "0.2.0"
4
4
  description = "Build agents on the Sofias agent graph and run them over RabbitMQ."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
7
- license = "Apache-2.0"
7
+ license = "LicenseRef-Sofias-SDK-Lite"
8
+ license-files = ["LICENSE"]
9
+ authors = [{ name = "Sofias Tech, S.L.", email = "support@sofias.ai" }]
10
+ keywords = ["agents", "ai", "llm", "rabbitmq", "sofias"]
11
+ classifiers = [
12
+ "Development Status :: 3 - Alpha",
13
+ "Intended Audience :: Developers",
14
+ "Operating System :: OS Independent",
15
+ "Programming Language :: Python :: 3",
16
+ "Programming Language :: Python :: 3.11",
17
+ "Programming Language :: Python :: 3.12",
18
+ "Programming Language :: Python :: 3.13",
19
+ "Topic :: Software Development :: Libraries",
20
+ "Typing :: Typed",
21
+ ]
8
22
  dependencies = [
9
23
  "pydantic>=2.0",
10
24
  "aio-pika>=9.0.0",
@@ -13,11 +27,19 @@ dependencies = [
13
27
  "httpx>=0.27.0",
14
28
  ]
15
29
 
30
+ [project.urls]
31
+ Homepage = "https://sofias.ai/"
32
+ Documentation = "https://docs.sofias.ai/"
33
+ Repository = "https://github.com/Sofias-ai/sofias-sdk-lite"
34
+ Changelog = "https://github.com/Sofias-ai/sofias-sdk-lite/blob/main/CHANGELOG.md"
35
+
16
36
  [project.optional-dependencies]
17
37
  otel = [
18
38
  "opentelemetry-api>=1.20.0",
19
39
  ]
20
40
  docs = [
41
+ # MkDocs 2.0 drops the plugin system this site relies on.
42
+ "mkdocs>=1.6,<2",
21
43
  "mkdocs-material>=9.5",
22
44
  "mkdocstrings[python]>=0.25",
23
45
  ]
@@ -91,7 +91,7 @@ from sofias_sdk_lite.errors import (
91
91
  ToolExecutionError,
92
92
  )
93
93
  from sofias_sdk_lite.llm import (
94
- BifrostLLM,
94
+ GatewayLLM,
95
95
  LLMCallable,
96
96
  LLMGatewayConfig,
97
97
  LLMResponse,
@@ -230,7 +230,7 @@ __all__ = [
230
230
  "StreamableLLMCallable",
231
231
  "LLMResponse",
232
232
  # LLM clients + factory
233
- "BifrostLLM",
233
+ "GatewayLLM",
234
234
  "OpenAICompatibleLLM",
235
235
  "LLMGatewayConfig",
236
236
  "create_llm",
@@ -68,13 +68,13 @@ class BaseAgentSettings(AgentSettings):
68
68
  """Model identifier or gateway alias. Empty means "no LLM configured here"."""
69
69
 
70
70
  router_url: str = ""
71
- """OpenAI-compatible gateway root. Empty falls back to the in-cluster Bifrost URL."""
71
+ """OpenAI-compatible gateway root, injected by the platform. Required to build an LLM."""
72
72
 
73
73
  router_api_key: SecretStr = SecretStr("")
74
74
  """Gateway bearer token. Empty sends unauthenticated requests."""
75
75
 
76
76
  router_provider: str = ""
77
- """Adapter flavour: ``"bifrost"`` (default when empty) or an OpenAI-compatible label."""
77
+ """Adapter flavour: ``"sofias"`` (default when empty) or an OpenAI-compatible label."""
78
78
 
79
79
  @property
80
80
  def has_llm_gateway(self) -> bool:
@@ -5,19 +5,19 @@ Two layers:
5
5
  - **Protocol** (`LLMCallable`, `StreamableLLMCallable`, `LLMResponse`,
6
6
  `TokenUsage`, `ToolSpec`, ...): the contract `LLMNode` drives. Wrap any
7
7
  client in it if you need something the bundled adapters do not cover.
8
- - **Batteries** (`create_llm`, `BifrostLLM`, `OpenAICompatibleLLM`,
9
- `LLMGatewayConfig`): a ready-made client for the Sofias Bifrost gateway (or
8
+ - **Batteries** (`create_llm`, `GatewayLLM`, `OpenAICompatibleLLM`,
9
+ `LLMGatewayConfig`): a ready-made client for the Sofias gateway (or
10
10
  any OpenAI-compatible endpoint) resolved from settings or the environment,
11
11
  so agent code never constructs an LLM client by hand.
12
12
  """
13
13
 
14
14
  from __future__ import annotations
15
15
 
16
- from sofias_sdk_lite.llm.bifrost import (
17
- DEFAULT_BIFROST_BASE_URL,
18
- DEFAULT_BIFROST_MAX_TOKENS,
19
- BifrostLLM,
20
- normalize_bifrost_base_url,
16
+ from sofias_sdk_lite.llm.gateway import (
17
+ DEFAULT_GATEWAY_MAX_TOKENS,
18
+ PROVIDER_GATEWAY,
19
+ GatewayLLM,
20
+ normalize_gateway_base_url,
21
21
  )
22
22
  from sofias_sdk_lite.llm.factory import (
23
23
  ENV_LLM_API_KEY,
@@ -52,11 +52,11 @@ __all__ = [
52
52
  "ToolCall",
53
53
  "ToolSpec",
54
54
  # Clients
55
- "BifrostLLM",
55
+ "GatewayLLM",
56
56
  "OpenAICompatibleLLM",
57
- "DEFAULT_BIFROST_BASE_URL",
58
- "DEFAULT_BIFROST_MAX_TOKENS",
59
- "normalize_bifrost_base_url",
57
+ "DEFAULT_GATEWAY_MAX_TOKENS",
58
+ "PROVIDER_GATEWAY",
59
+ "normalize_gateway_base_url",
60
60
  # Factory
61
61
  "LLMGatewayConfig",
62
62
  "create_llm",
@@ -6,10 +6,9 @@ Resolution order for `create_llm`:
6
6
  2. The agent's runtime settings (`BaseAgentSettings.model_name`,
7
7
  ``router_url``, ``router_api_key``), which the platform injects per task.
8
8
  3. Environment variables: ``SOFIAS_LLM_MODEL``, ``SOFIAS_LLM_BASE_URL``,
9
- ``SOFIAS_LLM_API_KEY``, ``SOFIAS_LLM_PROVIDER``; then ``BIFROST_MODEL`` /
10
- ``BIFROST_BASE_URL`` / ``BIFROST_API_KEY`` (what the Sofias Developer Portal
11
- injects into every agent container); then the platform's canonical
12
- ``MODEL_NAME`` / ``ROUTER_URL`` / ``ROUTER_API_KEY``.
9
+ ``SOFIAS_LLM_API_KEY``, ``SOFIAS_LLM_PROVIDER`` (what the Sofias platform
10
+ injects into every agent container); then ``MODEL_NAME`` / ``ROUTER_URL`` /
11
+ ``ROUTER_API_KEY``, the same keys the agent settings use.
13
12
 
14
13
  `AgentBuilder.build()` calls `resolve_default_llm` when no `with_llm()` was
15
14
  given, and `AgentRunner` scopes the per-task settings-derived client with
@@ -27,7 +26,7 @@ from typing import Any, Final
27
26
  from pydantic import BaseModel, ConfigDict, SecretStr
28
27
 
29
28
  from sofias_sdk_lite.errors.exceptions import LLMConfigurationError
30
- from sofias_sdk_lite.llm.bifrost import DEFAULT_BIFROST_BASE_URL, BifrostLLM
29
+ from sofias_sdk_lite.llm.gateway import PROVIDER_GATEWAY, GatewayLLM
31
30
  from sofias_sdk_lite.llm.openai_compatible import OpenAICompatibleLLM
32
31
  from sofias_sdk_lite.llm.protocol import LLMCallable, StreamableLLMCallable
33
32
  from sofias_sdk_lite.observability._log import get_logger
@@ -53,16 +52,12 @@ ENV_LLM_BASE_URL: Final[str] = "SOFIAS_LLM_BASE_URL"
53
52
  ENV_LLM_API_KEY: Final[str] = "SOFIAS_LLM_API_KEY"
54
53
  ENV_LLM_PROVIDER: Final[str] = "SOFIAS_LLM_PROVIDER"
55
54
 
56
- # Fallback names, tried in order after the SOFIAS_LLM_* variables:
57
- # - BIFROST_*: injected by the Sofias Developer Portal into sandbox and
58
- # production agent containers (AgentRuntime::ModelSelection#model_env).
59
- # - MODEL_NAME / ROUTER_URL / ROUTER_API_KEY: the platform's canonical
60
- # settings keys, so a container that already exports them needs no renaming.
61
- _ENV_FALLBACK_MODEL: Final[tuple[str, ...]] = ("BIFROST_MODEL", "MODEL_NAME")
62
- _ENV_FALLBACK_BASE_URL: Final[tuple[str, ...]] = ("BIFROST_BASE_URL", "ROUTER_URL")
63
- _ENV_FALLBACK_API_KEY: Final[tuple[str, ...]] = ("BIFROST_API_KEY", "ROUTER_API_KEY")
55
+ # Fallback names, tried after the SOFIAS_LLM_* variables: the same keys the
56
+ # agent settings use, so a container that already exports them needs no renaming.
57
+ _ENV_FALLBACK_MODEL: Final[tuple[str, ...]] = ("MODEL_NAME",)
58
+ _ENV_FALLBACK_BASE_URL: Final[tuple[str, ...]] = ("ROUTER_URL",)
59
+ _ENV_FALLBACK_API_KEY: Final[tuple[str, ...]] = ("ROUTER_API_KEY",)
64
60
 
65
- PROVIDER_BIFROST: Final[str] = "bifrost"
66
61
  _OPENAI_COMPATIBLE_PROVIDERS: Final[frozenset[str]] = frozenset(
67
62
  {"openai", "openai-compatible", "generic", "litellm", "openrouter", "vllm"}
68
63
  )
@@ -71,8 +66,9 @@ _OPENAI_COMPATIBLE_PROVIDERS: Final[frozenset[str]] = frozenset(
71
66
  class LLMGatewayConfig(BaseModel):
72
67
  """Everything needed to build an LLM client.
73
68
 
74
- ``model`` is the only required field. ``base_url`` defaults to the
75
- in-cluster Bifrost endpoint and ``provider`` to ``"bifrost"``.
69
+ ``model`` names the model; ``base_url`` must be set before `create_llm`
70
+ can build a client (the platform injects it). ``provider`` defaults to
71
+ ``"sofias"``, the Sofias gateway.
76
72
  """
77
73
 
78
74
  model_config = ConfigDict(frozen=True)
@@ -80,14 +76,14 @@ class LLMGatewayConfig(BaseModel):
80
76
  model: str
81
77
  """Model identifier or gateway alias (e.g. ``"default"``)."""
82
78
 
83
- base_url: str = DEFAULT_BIFROST_BASE_URL
84
- """OpenAI-compatible API root."""
79
+ base_url: str = ""
80
+ """OpenAI-compatible API root. Injected by the platform; required to build a client."""
85
81
 
86
82
  api_key: SecretStr = SecretStr("")
87
83
  """Bearer token. Empty sends no ``Authorization`` header."""
88
84
 
89
- provider: str = PROVIDER_BIFROST
90
- """``"bifrost"`` or any OpenAI-compatible label (``"openai"``, ``"litellm"``, ...)."""
85
+ provider: str = PROVIDER_GATEWAY
86
+ """``"sofias"`` or any OpenAI-compatible label (``"openai"``, ``"litellm"``, ...)."""
91
87
 
92
88
  temperature: float | None = None
93
89
  """Sampling temperature; ``None`` keeps the adapter default."""
@@ -102,7 +98,7 @@ class LLMGatewayConfig(BaseModel):
102
98
  """Retries on transient failures."""
103
99
 
104
100
  reasoning_effort: str | None = None
105
- """Bifrost only: overrides the per-model-family default."""
101
+ """Sofias gateway only: overrides the per-model-family default."""
106
102
 
107
103
  def with_overrides(self, **overrides: Any) -> LLMGatewayConfig:
108
104
  """Return a copy with the non-``None`` overrides applied."""
@@ -123,16 +119,16 @@ def _first_env(env: Mapping[str, str], primary: str, fallbacks: tuple[str, ...])
123
119
  def gateway_config_from_env(environ: Mapping[str, str] | None = None) -> LLMGatewayConfig | None:
124
120
  """Read gateway configuration from the environment; ``None`` if no model is set.
125
121
 
126
- ``SOFIAS_LLM_*`` wins, then the portal's ``BIFROST_*``, then
127
- ``MODEL_NAME`` / ``ROUTER_URL`` / ``ROUTER_API_KEY``.
122
+ ``SOFIAS_LLM_*`` wins, then ``MODEL_NAME`` / ``ROUTER_URL`` /
123
+ ``ROUTER_API_KEY``.
128
124
  """
129
125
  env = os.environ if environ is None else environ
130
126
  model = _first_env(env, ENV_LLM_MODEL, _ENV_FALLBACK_MODEL)
131
127
  if not model:
132
128
  return None
133
- base_url = _first_env(env, ENV_LLM_BASE_URL, _ENV_FALLBACK_BASE_URL) or DEFAULT_BIFROST_BASE_URL
129
+ base_url = _first_env(env, ENV_LLM_BASE_URL, _ENV_FALLBACK_BASE_URL)
134
130
  api_key = _first_env(env, ENV_LLM_API_KEY, _ENV_FALLBACK_API_KEY)
135
- provider = env.get(ENV_LLM_PROVIDER) or PROVIDER_BIFROST
131
+ provider = env.get(ENV_LLM_PROVIDER) or PROVIDER_GATEWAY
136
132
  return LLMGatewayConfig(
137
133
  model=model, base_url=base_url, api_key=SecretStr(api_key), provider=provider
138
134
  )
@@ -149,10 +145,10 @@ def gateway_config_from_settings(settings: Any) -> LLMGatewayConfig | None:
149
145
  model = getattr(settings, "model_name", "") or ""
150
146
  if not model:
151
147
  return None
152
- base_url = getattr(settings, "router_url", "") or DEFAULT_BIFROST_BASE_URL
148
+ base_url = getattr(settings, "router_url", "") or ""
153
149
  raw_key = getattr(settings, "router_api_key", "")
154
150
  api_key = raw_key.get_secret_value() if isinstance(raw_key, SecretStr) else str(raw_key or "")
155
- provider = getattr(settings, "router_provider", "") or PROVIDER_BIFROST
151
+ provider = getattr(settings, "router_provider", "") or PROVIDER_GATEWAY
156
152
  return LLMGatewayConfig(
157
153
  model=model, base_url=base_url, api_key=SecretStr(api_key), provider=provider
158
154
  )
@@ -204,14 +200,23 @@ def create_llm(
204
200
  source: An `LLMGatewayConfig`, an agent settings object exposing
205
201
  ``model_name`` / ``router_url`` / ``router_api_key``, or ``None``
206
202
  to fall back to keyword arguments and then the environment.
207
- model, base_url, api_key, provider, temperature, max_tokens, timeout,
208
- max_retries, reasoning_effort: Override the resolved configuration.
203
+ model: Overrides the resolved model identifier or gateway alias.
204
+ base_url: Overrides the resolved gateway URL.
205
+ api_key: Overrides the resolved bearer token.
206
+ provider: Overrides the adapter flavour (``"sofias"`` or an
207
+ OpenAI-compatible label).
208
+ temperature: Overrides the sampling temperature.
209
+ max_tokens: Overrides the output budget.
210
+ timeout: Overrides the per-request timeout in seconds.
211
+ max_retries: Overrides the number of retries on transient failures.
212
+ reasoning_effort: Overrides the per-model-family default (Sofias
213
+ gateway only).
209
214
  **adapter_kwargs: Forwarded to the adapter constructor (e.g.
210
215
  ``transport=`` for tests, ``default_headers=``).
211
216
 
212
217
  Raises:
213
- LLMConfigurationError: If no model can be resolved or the provider
214
- is unknown.
218
+ LLMConfigurationError: If no model or gateway URL can be resolved, or
219
+ the provider is unknown.
215
220
  """
216
221
  config = _resolve_config(
217
222
  source,
@@ -246,12 +251,20 @@ def create_llm(
246
251
  if config.temperature is not None:
247
252
  common["temperature"] = config.temperature
248
253
 
254
+ if not config.base_url.strip():
255
+ raise LLMConfigurationError(
256
+ f"No LLM gateway URL configured for model '{config.model}'. On the Sofias "
257
+ f"platform {ENV_LLM_BASE_URL} is injected automatically; to run locally, "
258
+ "export it or install a fake LLM with default_llm(...).",
259
+ missing=["base_url"],
260
+ )
261
+
249
262
  provider_name = config.provider.lower()
250
- if provider_name == PROVIDER_BIFROST:
251
- return BifrostLLM(reasoning_effort=config.reasoning_effort, **common)
263
+ if provider_name == PROVIDER_GATEWAY:
264
+ return GatewayLLM(reasoning_effort=config.reasoning_effort, **common)
252
265
  if provider_name in _OPENAI_COMPATIBLE_PROVIDERS:
253
266
  return OpenAICompatibleLLM(provider=provider_name, **common)
254
- supported = ", ".join(sorted({PROVIDER_BIFROST, *_OPENAI_COMPATIBLE_PROVIDERS}))
267
+ supported = ", ".join(sorted({PROVIDER_GATEWAY, *_OPENAI_COMPATIBLE_PROVIDERS}))
255
268
  raise LLMConfigurationError(
256
269
  f"Unknown LLM provider '{config.provider}'. Supported: {supported}",
257
270
  missing=["provider"],
@@ -1,13 +1,17 @@
1
- """Bifrost gateway client.
1
+ """Sofias gateway client.
2
2
 
3
- Bifrost is the OpenAI-compatible LLM gateway used by the Sofias platform. This
4
- adapter is `OpenAICompatibleLLM` with the gateway's defaults baked in:
3
+ The Sofias platform gives every agent access to its models through an
4
+ OpenAI-compatible gateway. This adapter is `OpenAICompatibleLLM` with the
5
+ gateway's defaults baked in:
5
6
 
6
- - base URL ``http://bifrost:8080/v1`` (the in-cluster service name);
7
7
  - a per-model-family ``reasoning_effort`` so thinking channels are switched
8
8
  off (or minimised) unless the caller asks otherwise;
9
9
  - a generous ``max_tokens`` budget, because structured output is paid out
10
10
  of that budget and a truncated JSON document does not parse.
11
+
12
+ There is no default address: when the agent runs on the platform the gateway
13
+ URL is injected for it (``SOFIAS_LLM_BASE_URL``), and to run locally against a
14
+ real gateway you set it yourself.
11
15
  """
12
16
 
13
17
  from __future__ import annotations
@@ -17,19 +21,20 @@ from urllib.parse import urlsplit
17
21
 
18
22
  import httpx
19
23
 
24
+ from sofias_sdk_lite.errors.exceptions import LLMConfigurationError
20
25
  from sofias_sdk_lite.llm.openai_compatible import OpenAICompatibleLLM
21
26
 
22
27
  __all__ = [
23
- "BifrostLLM",
24
- "DEFAULT_BIFROST_BASE_URL",
25
- "DEFAULT_BIFROST_MAX_TOKENS",
26
- "normalize_bifrost_base_url",
28
+ "DEFAULT_GATEWAY_MAX_TOKENS",
29
+ "GatewayLLM",
30
+ "PROVIDER_GATEWAY",
31
+ "normalize_gateway_base_url",
27
32
  ]
28
33
 
29
- DEFAULT_BIFROST_BASE_URL: Final[str] = "http://bifrost:8080/v1"
30
- """In-cluster Bifrost endpoint used when no base URL is configured."""
34
+ PROVIDER_GATEWAY: Final[str] = "sofias"
35
+ """Provider label that selects this adapter in `create_llm`."""
31
36
 
32
- DEFAULT_BIFROST_MAX_TOKENS: Final[int] = 16_384
37
+ DEFAULT_GATEWAY_MAX_TOKENS: Final[int] = 16_384
33
38
  """Output budget sent when neither the constructor nor the caller sets one.
34
39
 
35
40
  A single budget on purpose: splitting it by reasoning mode produced a family
@@ -39,9 +44,9 @@ billed, so a generous cap costs nothing on short completions.
39
44
 
40
45
  # Per-family default ``reasoning_effort`` when the caller passes none.
41
46
  # ``"none"`` turns the thinking channel off, ``"low"`` keeps it minimal.
42
- # - gpt-oss reasons by default and some providers reject "none" -> "low".
43
- # - deepseek: the primary provider rejects "none" with HTTP 400 -> "low".
44
- # - qwen: thinking is inconsistent across providers -> "none" explicitly.
47
+ # - gpt-oss reasons by default and "none" is not accepted everywhere -> "low".
48
+ # - deepseek: "none" is not accepted everywhere -> "low".
49
+ # - qwen: thinking behaves inconsistently unless disabled -> "none" explicitly.
45
50
  # - glm: "none" makes the model emit its monologue inside content -> "low".
46
51
  _REASONING_EFFORT_BY_FAMILY: Final[dict[str, str]] = {
47
52
  "gpt-oss": "low",
@@ -51,43 +56,55 @@ _REASONING_EFFORT_BY_FAMILY: Final[dict[str, str]] = {
51
56
  }
52
57
 
53
58
  # Fallback for models outside the table, including the ``"default"`` gateway
54
- # alias most agents send: ``"low"`` is accepted by every upstream provider.
59
+ # alias most agents send: ``"low"`` is accepted by every model family.
55
60
  _REASONING_EFFORT_FALLBACK: Final[str] = "low"
56
61
 
57
62
 
58
- def normalize_bifrost_base_url(base_url: str) -> str:
59
- """Return the OpenAI-compatible API root for a Bifrost host.
63
+ def normalize_gateway_base_url(base_url: str) -> str:
64
+ """Return the OpenAI-compatible API root for a gateway host.
65
+
66
+ The gateway can be configured either as a bare host
67
+ (``https://gateway.example``) or as the API root
68
+ (``https://gateway.example/v1``). The OpenAI surface lives under ``/v1``,
69
+ so a URL with no path gets it appended; any URL that already has a path is
70
+ trusted as-is.
60
71
 
61
- Deployments configure the gateway either as a bare host
62
- (``https://bifrost.example``) or as the API root
63
- (``https://bifrost.example/v1``). Bifrost serves the OpenAI surface under
64
- ``/v1``, so a URL with no path gets it appended; any URL that already has
65
- a path is trusted as-is. Empty input falls back to the in-cluster default.
72
+ Raises:
73
+ LLMConfigurationError: If ``base_url`` is empty.
66
74
  """
67
- url = (base_url or DEFAULT_BIFROST_BASE_URL).rstrip("/")
75
+ url = (base_url or "").strip().rstrip("/")
76
+ if not url:
77
+ raise LLMConfigurationError(
78
+ "No LLM gateway URL configured. On the Sofias platform "
79
+ "SOFIAS_LLM_BASE_URL is injected automatically; to run locally, "
80
+ "export it or install a fake LLM with default_llm(...).",
81
+ missing=["base_url"],
82
+ )
68
83
  if urlsplit(url).path in ("", "/"):
69
84
  return f"{url}/v1"
70
85
  return url
71
86
 
72
87
 
73
- class BifrostLLM(OpenAICompatibleLLM):
74
- """`StreamableLLMCallable` for the Bifrost gateway.
88
+ class GatewayLLM(OpenAICompatibleLLM):
89
+ """`StreamableLLMCallable` for the Sofias gateway.
75
90
 
76
91
  Args:
77
- api_key: Bifrost API key (empty string sends no ``Authorization``).
92
+ api_key: Gateway API key (empty string sends no ``Authorization``).
78
93
  model: Model identifier or gateway alias (e.g. ``"default"``).
79
- base_url: Gateway host or API root; defaults to the in-cluster
80
- service URL. A bare host gets ``/v1`` appended (see
81
- `normalize_bifrost_base_url`).
94
+ base_url: Gateway host or API root. Required; a bare host gets
95
+ ``/v1`` appended (see `normalize_gateway_base_url`).
82
96
  temperature: Sampling temperature.
83
97
  max_retries: Retries on transient failures.
84
98
  timeout: Per-request timeout in seconds.
85
99
  reasoning_effort: ``None`` applies the per-family default; a non-empty
86
100
  string is sent as-is on every request; ``""`` disables injection
87
- so the provider default applies.
88
- max_tokens: Output budget; ``None`` applies `DEFAULT_BIFROST_MAX_TOKENS`.
101
+ so the model default applies.
102
+ max_tokens: Output budget; ``None`` applies `DEFAULT_GATEWAY_MAX_TOKENS`.
89
103
  default_headers: Extra headers sent on every request.
90
104
  transport: Optional ``httpx`` transport (for tests).
105
+
106
+ Raises:
107
+ LLMConfigurationError: If ``base_url`` is empty.
91
108
  """
92
109
 
93
110
  def __init__(
@@ -95,7 +112,7 @@ class BifrostLLM(OpenAICompatibleLLM):
95
112
  *,
96
113
  api_key: str,
97
114
  model: str,
98
- base_url: str = DEFAULT_BIFROST_BASE_URL,
115
+ base_url: str,
99
116
  temperature: float = 0.1,
100
117
  max_retries: int = 3,
101
118
  timeout: float = 120.0,
@@ -106,9 +123,9 @@ class BifrostLLM(OpenAICompatibleLLM):
106
123
  ) -> None:
107
124
  super().__init__(
108
125
  api_key=api_key,
109
- base_url=normalize_bifrost_base_url(base_url),
126
+ base_url=normalize_gateway_base_url(base_url),
110
127
  model=model,
111
- provider="bifrost",
128
+ provider=PROVIDER_GATEWAY,
112
129
  temperature=temperature,
113
130
  max_retries=max_retries,
114
131
  timeout=timeout,
@@ -126,10 +143,10 @@ class BifrostLLM(OpenAICompatibleLLM):
126
143
  return _REASONING_EFFORT_FALLBACK
127
144
 
128
145
  def _augment_request_kwargs(self, kwargs: dict[str, Any]) -> None:
129
- """Inject Bifrost defaults; values already present in the request win."""
146
+ """Inject gateway defaults; values already present in the request win."""
130
147
  if self._reasoning_effort is None:
131
148
  model = kwargs.get("model") or self._model
132
149
  kwargs.setdefault("reasoning_effort", self._default_reasoning_effort(str(model)))
133
150
  elif self._reasoning_effort:
134
151
  kwargs.setdefault("reasoning_effort", self._reasoning_effort)
135
- kwargs.setdefault("max_tokens", DEFAULT_BIFROST_MAX_TOKENS)
152
+ kwargs.setdefault("max_tokens", DEFAULT_GATEWAY_MAX_TOKENS)
@@ -1,7 +1,7 @@
1
1
  """OpenAI-compatible chat-completions client implementing `StreamableLLMCallable`.
2
2
 
3
3
  Any gateway or provider that speaks the OpenAI ``/chat/completions`` wire
4
- format (Bifrost, LiteLLM, OpenRouter, vLLM, OpenAI itself, ...) works with
4
+ format (the Sofias gateway, LiteLLM, OpenRouter, vLLM, OpenAI itself, ...) works with
5
5
  this adapter. It is built on ``httpx`` only, so the SDK stays free of any
6
6
  vendor SDK.
7
7
 
@@ -71,7 +71,7 @@ class OpenAICompatibleLLM:
71
71
  ``MockTransport`` here).
72
72
  """
73
73
 
74
- GATEWAY_PROVIDERS: ClassVar[frozenset[str]] = frozenset({"bifrost", "litellm", "openrouter"})
74
+ GATEWAY_PROVIDERS: ClassVar[frozenset[str]] = frozenset({"sofias", "litellm", "openrouter"})
75
75
 
76
76
  def __init__(
77
77
  self,
@@ -1,7 +1,7 @@
1
1
  """The `LLMCallable` protocol and its request/response types.
2
2
 
3
3
  This module defines the contract `LLMNode` drives. The SDK ships two
4
- implementations (`sofias_sdk_lite.llm.BifrostLLM` for the Sofias gateway and
4
+ implementations (`sofias_sdk_lite.llm.GatewayLLM` for the Sofias gateway and
5
5
  `sofias_sdk_lite.llm.OpenAICompatibleLLM` for any OpenAI-style endpoint) and a
6
6
  factory (`sofias_sdk_lite.llm.create_llm`) that picks one from settings or the
7
7
  environment. Implement the protocol yourself only when you need a client those
@@ -1,6 +1,6 @@
1
1
  """Observability protocols for sofias_sdk_lite: tracing and events.
2
2
 
3
- Protocol-only — no concrete OTLP/SigNoz exporter or message broker client
3
+ Protocol-only — no concrete OTLP exporter or message broker client
4
4
  ships here. Bring your own tracing backend (OpenTelemetry, Jaeger,
5
5
  Datadog, ...) and event broker (RabbitMQ, Kafka, ...) by implementing the
6
6
  protocols below.
@@ -6,7 +6,7 @@ protocols the SDK expects from an external tracing system, the
6
6
  node, tool, and LLM operations), and no-op / logging-only implementations
7
7
  for when a real tracing backend isn't configured.
8
8
 
9
- Protocol-only: no concrete OpenTelemetry/OTLP/SigNoz exporter is vendored.
9
+ Protocol-only: no concrete OpenTelemetry/OTLP exporter is vendored.
10
10
  Bring your own backend by implementing ``TracingProvider``.
11
11
  """
12
12