sofias-sdk-lite 0.1.2__tar.gz → 0.1.3__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.
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/PKG-INFO +10 -1
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/README.md +7 -0
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/pyproject.toml +8 -2
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/pyproject.toml.orig +8 -2
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/__init__.py +18 -2
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/agent/__init__.py +2 -0
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/agent/execution_context.py +44 -1
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/config/__init__.py +4 -0
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/config/agent_settings.py +19 -1
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/config/defaults.py +15 -0
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/nodes/llm_node.py +334 -64
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/nodes/llm_node_config.py +11 -0
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/observability/__init__.py +10 -0
- sofias_sdk_lite-0.1.3/src/sofias_sdk_lite/observability/trace_context.py +134 -0
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/rabbitmq/__init__.py +2 -1
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/rabbitmq/consumer.py +13 -1
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/rabbitmq/publisher.py +19 -5
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/rabbitmq/types.py +25 -0
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/runner/runner.py +119 -3
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/state/__init__.py +7 -1
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/state/history.py +31 -1
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/workflows/__init__.py +8 -3
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/workflows/chat.py +52 -12
- sofias_sdk_lite-0.1.3/src/sofias_sdk_lite/workflows/streaming_chat.py +320 -0
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/agent/agent.py +0 -0
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/agent/agent_builder.py +0 -0
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/agent/agent_config.py +0 -0
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/agent/middleware.py +0 -0
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/agent/response_workflow.py +0 -0
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/agent/streaming.py +0 -0
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/config/runtime_config.py +0 -0
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/config/sdk_config.py +0 -0
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/config/source.py +0 -0
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/contracts/__init__.py +0 -0
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/contracts/agent_contracts.py +0 -0
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/contracts/base_contracts.py +0 -0
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/contracts/node_contracts.py +0 -0
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/contracts/strict_contract.py +0 -0
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/errors/__init__.py +0 -0
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/errors/circuit_breaker.py +0 -0
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/errors/error_handler.py +0 -0
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/errors/exceptions.py +0 -0
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/llm/__init__.py +0 -0
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/llm/protocol.py +0 -0
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/llm/tokens.py +0 -0
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/llm/tools.py +0 -0
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/messaging/__init__.py +0 -0
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/messaging/models.py +0 -0
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/nodes/__init__.py +0 -0
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/nodes/aggregator_config.py +0 -0
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/nodes/aggregator_node.py +0 -0
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/nodes/base_node.py +0 -0
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/nodes/delegation_config.py +0 -0
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/nodes/delegation_node.py +0 -0
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/nodes/delegation_transport.py +0 -0
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/nodes/function_node.py +0 -0
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/nodes/plan_executor.py +0 -0
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/nodes/planner_node.py +0 -0
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/nodes/planning_models.py +0 -0
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/nodes/prompt_assembler.py +0 -0
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/observability/_log.py +0 -0
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/observability/events.py +0 -0
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/observability/tracing.py +0 -0
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/py.typed +0 -0
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/rabbitmq/client.py +0 -0
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/rabbitmq/config.py +0 -0
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/rabbitmq/delegation_transport.py +0 -0
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/rabbitmq/rpc_client.py +0 -0
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/routing/__init__.py +0 -0
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/routing/router.py +0 -0
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/routing/strategies.py +0 -0
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/runner/__init__.py +0 -0
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/runner/config.py +0 -0
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/state/conversation_state.py +0 -0
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/state/memory.py +0 -0
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/tools.py +0 -0
- {sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/workflows/null.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sofias-sdk-lite
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.3
|
|
4
4
|
Summary: Build agents on the Sofias agent graph and run them over RabbitMQ.
|
|
5
5
|
License-Expression: Apache-2.0
|
|
6
6
|
Requires-Dist: pydantic>=2.0
|
|
@@ -9,8 +9,10 @@ Requires-Dist: rstream>=1.0.0
|
|
|
9
9
|
Requires-Dist: nh3>=0.3.6
|
|
10
10
|
Requires-Dist: mkdocs-material>=9.5 ; extra == 'docs'
|
|
11
11
|
Requires-Dist: mkdocstrings[python]>=0.25 ; extra == 'docs'
|
|
12
|
+
Requires-Dist: opentelemetry-api>=1.20.0 ; extra == 'otel'
|
|
12
13
|
Requires-Python: >=3.11
|
|
13
14
|
Provides-Extra: docs
|
|
15
|
+
Provides-Extra: otel
|
|
14
16
|
Description-Content-Type: text/markdown
|
|
15
17
|
|
|
16
18
|
# sofias-sdk-lite
|
|
@@ -138,6 +140,13 @@ if __name__ == "__main__":
|
|
|
138
140
|
).run()
|
|
139
141
|
```
|
|
140
142
|
|
|
143
|
+
## Optional extras
|
|
144
|
+
|
|
145
|
+
- `sofias-sdk-lite[otel]` — installs `opentelemetry-api` so the runner opens
|
|
146
|
+
an `agent.handle` span per turn and response fragments carry the active
|
|
147
|
+
span's `traceparent`. Without it, the inbound `traceparent` is still echoed
|
|
148
|
+
end to end.
|
|
149
|
+
|
|
141
150
|
## Scope (v1)
|
|
142
151
|
|
|
143
152
|
Core agent graph, RabbitMQ messaging, and the runner ship today. Memory,
|
|
@@ -123,6 +123,13 @@ if __name__ == "__main__":
|
|
|
123
123
|
).run()
|
|
124
124
|
```
|
|
125
125
|
|
|
126
|
+
## Optional extras
|
|
127
|
+
|
|
128
|
+
- `sofias-sdk-lite[otel]` — installs `opentelemetry-api` so the runner opens
|
|
129
|
+
an `agent.handle` span per turn and response fragments carry the active
|
|
130
|
+
span's `traceparent`. Without it, the inbound `traceparent` is still echoed
|
|
131
|
+
end to end.
|
|
132
|
+
|
|
126
133
|
## Scope (v1)
|
|
127
134
|
|
|
128
135
|
Core agent graph, RabbitMQ messaging, and the runner ship today. Memory,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "sofias-sdk-lite"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.3"
|
|
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"
|
|
@@ -13,6 +13,7 @@ dependencies = [
|
|
|
13
13
|
]
|
|
14
14
|
|
|
15
15
|
[project.optional-dependencies]
|
|
16
|
+
otel = ["opentelemetry-api>=1.20.0"]
|
|
16
17
|
docs = [
|
|
17
18
|
"mkdocs-material>=9.5",
|
|
18
19
|
"mkdocstrings[python]>=0.25",
|
|
@@ -24,7 +25,10 @@ url = "https://pypi.org/simple"
|
|
|
24
25
|
default = true
|
|
25
26
|
|
|
26
27
|
[tool.pytest.ini_options]
|
|
27
|
-
pythonpath = [
|
|
28
|
+
pythonpath = [
|
|
29
|
+
"src",
|
|
30
|
+
".",
|
|
31
|
+
]
|
|
28
32
|
addopts = "-ra"
|
|
29
33
|
asyncio_mode = "auto"
|
|
30
34
|
markers = ["integration: requires a running RabbitMQ broker"]
|
|
@@ -48,4 +52,6 @@ dev = [
|
|
|
48
52
|
"pytest-cov>=5.0",
|
|
49
53
|
"ruff>=0.4.0",
|
|
50
54
|
"pyright>=1.1.408",
|
|
55
|
+
"opentelemetry-api>=1.20.0",
|
|
56
|
+
"opentelemetry-sdk>=1.20.0",
|
|
51
57
|
]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "sofias-sdk-lite"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.3"
|
|
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"
|
|
@@ -13,6 +13,9 @@ dependencies = [
|
|
|
13
13
|
]
|
|
14
14
|
|
|
15
15
|
[project.optional-dependencies]
|
|
16
|
+
otel = [
|
|
17
|
+
"opentelemetry-api>=1.20.0",
|
|
18
|
+
]
|
|
16
19
|
docs = [
|
|
17
20
|
"mkdocs-material>=9.5",
|
|
18
21
|
"mkdocstrings[python]>=0.25",
|
|
@@ -34,10 +37,13 @@ dev = [
|
|
|
34
37
|
"pytest-cov>=5.0",
|
|
35
38
|
"ruff>=0.4.0",
|
|
36
39
|
"pyright>=1.1.408",
|
|
40
|
+
# Exercise the optional OpenTelemetry path (the `[otel]` extra) in tests.
|
|
41
|
+
"opentelemetry-api>=1.20.0",
|
|
42
|
+
"opentelemetry-sdk>=1.20.0",
|
|
37
43
|
]
|
|
38
44
|
|
|
39
45
|
[tool.pytest.ini_options]
|
|
40
|
-
pythonpath = ["src"]
|
|
46
|
+
pythonpath = ["src", "."]
|
|
41
47
|
addopts = "-ra"
|
|
42
48
|
asyncio_mode = "auto"
|
|
43
49
|
markers = ["integration: requires a running RabbitMQ broker"]
|
|
@@ -30,6 +30,8 @@ against RabbitMQ, streaming, delegation, and testing.
|
|
|
30
30
|
|
|
31
31
|
from __future__ import annotations
|
|
32
32
|
|
|
33
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
34
|
+
|
|
33
35
|
from sofias_sdk_lite.agent import (
|
|
34
36
|
Agent,
|
|
35
37
|
AgentBuildError,
|
|
@@ -45,6 +47,7 @@ from sofias_sdk_lite.agent import (
|
|
|
45
47
|
StreamingResponseWorkflow,
|
|
46
48
|
get_execution_context,
|
|
47
49
|
set_execution_context,
|
|
50
|
+
usage_state_from_list,
|
|
48
51
|
)
|
|
49
52
|
from sofias_sdk_lite.config import (
|
|
50
53
|
AgentSettings,
|
|
@@ -143,10 +146,20 @@ from sofias_sdk_lite.state import (
|
|
|
143
146
|
InMemoryStateProvider,
|
|
144
147
|
MemoryProvider,
|
|
145
148
|
Message,
|
|
149
|
+
SummarizingHistoryProvider,
|
|
150
|
+
)
|
|
151
|
+
from sofias_sdk_lite.workflows import (
|
|
152
|
+
BaseStreamingResponseWorkflow,
|
|
153
|
+
ChatResponseWorkflow,
|
|
154
|
+
NullWorkflow,
|
|
146
155
|
)
|
|
147
|
-
from sofias_sdk_lite.workflows import ChatResponseWorkflow, NullWorkflow
|
|
148
156
|
|
|
149
|
-
|
|
157
|
+
try:
|
|
158
|
+
# Derived from the installed distribution so it never drifts from
|
|
159
|
+
# pyproject.toml (CI rewrites the version there on tagged releases).
|
|
160
|
+
__version__ = version("sofias-sdk-lite")
|
|
161
|
+
except PackageNotFoundError: # pragma: no cover - source checkout without install
|
|
162
|
+
__version__ = "0.0.0"
|
|
150
163
|
|
|
151
164
|
__all__ = [
|
|
152
165
|
"__version__",
|
|
@@ -161,6 +174,7 @@ __all__ = [
|
|
|
161
174
|
"ExecutionContext",
|
|
162
175
|
"get_execution_context",
|
|
163
176
|
"set_execution_context",
|
|
177
|
+
"usage_state_from_list",
|
|
164
178
|
"ResponseWorkflow",
|
|
165
179
|
"StreamingResponseWorkflow",
|
|
166
180
|
"BaseDelegationResponseWorkflow",
|
|
@@ -251,12 +265,14 @@ __all__ = [
|
|
|
251
265
|
"RunnerConfig",
|
|
252
266
|
# Workflows
|
|
253
267
|
"ChatResponseWorkflow",
|
|
268
|
+
"BaseStreamingResponseWorkflow",
|
|
254
269
|
"NullWorkflow",
|
|
255
270
|
# State
|
|
256
271
|
"ConversationStateProvider",
|
|
257
272
|
"InMemoryStateProvider",
|
|
258
273
|
"MemoryProvider",
|
|
259
274
|
"HistoryProvider",
|
|
275
|
+
"SummarizingHistoryProvider",
|
|
260
276
|
"InMemoryHistory",
|
|
261
277
|
"Message",
|
|
262
278
|
]
|
|
@@ -8,6 +8,7 @@ from sofias_sdk_lite.agent.execution_context import (
|
|
|
8
8
|
TokenAccumulator,
|
|
9
9
|
get_execution_context,
|
|
10
10
|
set_execution_context,
|
|
11
|
+
usage_state_from_list,
|
|
11
12
|
)
|
|
12
13
|
from sofias_sdk_lite.agent.middleware import (
|
|
13
14
|
AgentMiddleware,
|
|
@@ -39,6 +40,7 @@ __all__ = [
|
|
|
39
40
|
"set_execution_context",
|
|
40
41
|
"ExecutionContext",
|
|
41
42
|
"TokenAccumulator",
|
|
43
|
+
"usage_state_from_list",
|
|
42
44
|
# Builder
|
|
43
45
|
"AgentBuilder",
|
|
44
46
|
"AgentBuildError",
|
{sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/agent/execution_context.py
RENAMED
|
@@ -10,7 +10,7 @@ from __future__ import annotations
|
|
|
10
10
|
from contextvars import ContextVar
|
|
11
11
|
from dataclasses import dataclass
|
|
12
12
|
from datetime import datetime
|
|
13
|
-
from typing import TYPE_CHECKING, Any
|
|
13
|
+
from typing import TYPE_CHECKING, Any, cast
|
|
14
14
|
|
|
15
15
|
from pydantic import BaseModel, ConfigDict, Field
|
|
16
16
|
|
|
@@ -22,6 +22,7 @@ __all__ = [
|
|
|
22
22
|
"ExecutionContext",
|
|
23
23
|
"get_execution_context",
|
|
24
24
|
"set_execution_context",
|
|
25
|
+
"usage_state_from_list",
|
|
25
26
|
]
|
|
26
27
|
|
|
27
28
|
|
|
@@ -136,6 +137,48 @@ class TokenAccumulator:
|
|
|
136
137
|
return result
|
|
137
138
|
|
|
138
139
|
|
|
140
|
+
def _usage_entry(entry: Any, key: str, default: Any = 0) -> Any:
|
|
141
|
+
"""Read *key* off a usage entry that may be a dict or an object.
|
|
142
|
+
|
|
143
|
+
``AgentResponse.usage`` entries are typed as ``dict`` (built by
|
|
144
|
+
``TokenAccumulator.to_usage_list``), but callers are free to set the
|
|
145
|
+
field directly with plain objects, so both shapes must work.
|
|
146
|
+
"""
|
|
147
|
+
if isinstance(entry, dict):
|
|
148
|
+
return cast(dict[str, Any], entry).get(key, default)
|
|
149
|
+
return getattr(entry, key, default)
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def _usage_entry_int(entry: Any, key: str) -> int:
|
|
153
|
+
try:
|
|
154
|
+
return int(_usage_entry(entry, key, 0) or 0)
|
|
155
|
+
except (TypeError, ValueError):
|
|
156
|
+
return 0
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def usage_state_from_list(usage: list[Any] | None) -> dict[str, Any] | None:
|
|
160
|
+
"""Collapse an ``AgentResponse.usage`` list into a single ``StreamFragment``
|
|
161
|
+
``state.usage`` object, or ``None`` when there is nothing to report.
|
|
162
|
+
|
|
163
|
+
Every response workflow that publishes a terminal fragment should call
|
|
164
|
+
this and merge the result into ``state``: it is the one place a billing
|
|
165
|
+
consumer reads token usage from. Sums tokens across every LLM call in the
|
|
166
|
+
turn (a turn can invoke several models: the main chat call plus e.g. an
|
|
167
|
+
embedding call for RAG), and names the entry with the most completion
|
|
168
|
+
tokens as ``model``, which picks the actual generation call over
|
|
169
|
+
near-zero-completion side calls.
|
|
170
|
+
"""
|
|
171
|
+
if not usage:
|
|
172
|
+
return None
|
|
173
|
+
|
|
174
|
+
primary = max(usage, key=lambda e: _usage_entry_int(e, "completion_tokens"))
|
|
175
|
+
return {
|
|
176
|
+
"prompt_tokens": sum(_usage_entry_int(e, "prompt_tokens") for e in usage),
|
|
177
|
+
"completion_tokens": sum(_usage_entry_int(e, "completion_tokens") for e in usage),
|
|
178
|
+
"model": _usage_entry(primary, "model_requested", ""),
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
|
|
139
182
|
class ExecutionContext(BaseModel):
|
|
140
183
|
"""Structured execution context propagated via ContextVar.
|
|
141
184
|
|
|
@@ -6,12 +6,14 @@ from sofias_sdk_lite.config.defaults import (
|
|
|
6
6
|
DEFAULT_MAX_ITERATIONS,
|
|
7
7
|
DEFAULT_MAX_RETRIES,
|
|
8
8
|
DEFAULT_MAX_TOKENS,
|
|
9
|
+
DEFAULT_MAX_TOOL_LOOP_TOKENS,
|
|
9
10
|
DEFAULT_MODEL,
|
|
10
11
|
DEFAULT_RETRY_BACKOFF_MULTIPLIER,
|
|
11
12
|
DEFAULT_RETRY_DELAY_SECONDS,
|
|
12
13
|
DEFAULT_RETRY_MAX_DELAY_SECONDS,
|
|
13
14
|
DEFAULT_STRICT_VALIDATION,
|
|
14
15
|
DEFAULT_TEMPERATURE,
|
|
16
|
+
DEFAULT_TOOL_LOOP_TOKEN_RESERVE,
|
|
15
17
|
DEFAULT_TOP_P,
|
|
16
18
|
DEFAULT_VERBOSE_LOGGING,
|
|
17
19
|
)
|
|
@@ -38,12 +40,14 @@ __all__ = [
|
|
|
38
40
|
"DEFAULT_MAX_ITERATIONS",
|
|
39
41
|
"DEFAULT_MAX_RETRIES",
|
|
40
42
|
"DEFAULT_MAX_TOKENS",
|
|
43
|
+
"DEFAULT_MAX_TOOL_LOOP_TOKENS",
|
|
41
44
|
"DEFAULT_MODEL",
|
|
42
45
|
"DEFAULT_RETRY_BACKOFF_MULTIPLIER",
|
|
43
46
|
"DEFAULT_RETRY_DELAY_SECONDS",
|
|
44
47
|
"DEFAULT_RETRY_MAX_DELAY_SECONDS",
|
|
45
48
|
"DEFAULT_STRICT_VALIDATION",
|
|
46
49
|
"DEFAULT_TEMPERATURE",
|
|
50
|
+
"DEFAULT_TOOL_LOOP_TOKEN_RESERVE",
|
|
47
51
|
"DEFAULT_TOP_P",
|
|
48
52
|
"DEFAULT_VERBOSE_LOGGING",
|
|
49
53
|
# SDK Config
|
{sofias_sdk_lite-0.1.2 → sofias_sdk_lite-0.1.3}/src/sofias_sdk_lite/config/agent_settings.py
RENAMED
|
@@ -15,7 +15,7 @@ whatever fields their own agent actually needs:
|
|
|
15
15
|
from __future__ import annotations
|
|
16
16
|
|
|
17
17
|
import difflib
|
|
18
|
-
from typing import Any
|
|
18
|
+
from typing import Any, ClassVar
|
|
19
19
|
|
|
20
20
|
from pydantic import ConfigDict, model_validator
|
|
21
21
|
|
|
@@ -41,6 +41,24 @@ class BaseAgentSettings(AgentSettings):
|
|
|
41
41
|
|
|
42
42
|
model_config = ConfigDict(extra="ignore", validate_default=True)
|
|
43
43
|
|
|
44
|
+
CREDENTIAL_FIELDS: ClassVar[frozenset[str]] = frozenset()
|
|
45
|
+
"""Names of fields that hold credentials (API keys, tokens, secrets).
|
|
46
|
+
|
|
47
|
+
Declare them on your subclass, ideally typed as ``pydantic.SecretStr`` so
|
|
48
|
+
``repr``/``model_dump`` never leak the raw value. The SDK excludes these
|
|
49
|
+
fields wherever settings are dumped into a dict that reaches an LLM prompt
|
|
50
|
+
(``LLMNode`` template variables), so a ``{api_key}`` placeholder can never
|
|
51
|
+
inline a secret. Read them at the point of use with ``.get_secret_value()``.
|
|
52
|
+
|
|
53
|
+
Example::
|
|
54
|
+
|
|
55
|
+
class MySettings(BaseAgentSettings):
|
|
56
|
+
CREDENTIAL_FIELDS = frozenset({"api_key"})
|
|
57
|
+
|
|
58
|
+
model_name: str = "gpt-4o-mini"
|
|
59
|
+
api_key: SecretStr = SecretStr("")
|
|
60
|
+
"""
|
|
61
|
+
|
|
44
62
|
@model_validator(mode="before")
|
|
45
63
|
@classmethod
|
|
46
64
|
def _warn_on_typo_keys(cls, data: Any) -> Any:
|
|
@@ -29,6 +29,19 @@ DEFAULT_TOP_P: Final[float] = 1.0
|
|
|
29
29
|
DEFAULT_MAX_ITERATIONS: Final[int] = 10
|
|
30
30
|
"""Default maximum iterations for a node's tool loop."""
|
|
31
31
|
|
|
32
|
+
DEFAULT_MAX_TOOL_LOOP_TOKENS: Final[int] = 128_000
|
|
33
|
+
"""Token budget for the WHOLE request of a tool-loop iteration.
|
|
34
|
+
|
|
35
|
+
The budget means the model's context window, not "what is left for the
|
|
36
|
+
history". The fixed prefix (system prompt + user prompt + tool schemas) is
|
|
37
|
+
*measured* on every iteration and counted against this number, together with
|
|
38
|
+
the accumulated tool-loop history. An agent running a model with a larger
|
|
39
|
+
window should raise it via ``NodeToolLoopConfig.max_tool_loop_tokens``.
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
DEFAULT_TOOL_LOOP_TOKEN_RESERVE: Final[int] = 16_384
|
|
43
|
+
"""Tokens reserved for the final LLM response within the tool-loop budget."""
|
|
44
|
+
|
|
32
45
|
DEFAULT_ITERATION_TIMEOUT_SECONDS: Final[float] = 60.0
|
|
33
46
|
"""Default timeout in seconds for a single tool loop iteration."""
|
|
34
47
|
|
|
@@ -68,6 +81,8 @@ __all__ = [
|
|
|
68
81
|
"DEFAULT_MAX_TOKENS",
|
|
69
82
|
"DEFAULT_TOP_P",
|
|
70
83
|
"DEFAULT_MAX_ITERATIONS",
|
|
84
|
+
"DEFAULT_MAX_TOOL_LOOP_TOKENS",
|
|
85
|
+
"DEFAULT_TOOL_LOOP_TOKEN_RESERVE",
|
|
71
86
|
"DEFAULT_ITERATION_TIMEOUT_SECONDS",
|
|
72
87
|
"DEFAULT_MAX_RETRIES",
|
|
73
88
|
"DEFAULT_RETRY_DELAY_SECONDS",
|