sofias-sdk-lite 0.4.0__tar.gz → 0.4.1__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.4.0 → sofias_sdk_lite-0.4.1}/PKG-INFO +1 -1
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/pyproject.toml +4 -1
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/pyproject.toml.orig +8 -1
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/nodes/llm_node.py +43 -8
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/nodes/prompt_assembler.py +65 -1
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/LICENSE +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/README.md +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/__init__.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/agent/__init__.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/agent/agent.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/agent/agent_builder.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/agent/agent_config.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/agent/execution_context.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/agent/middleware.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/agent/response_workflow.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/agent/streaming.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/config/__init__.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/config/agent_settings.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/config/defaults.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/config/runtime_config.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/config/sdk_config.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/config/source.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/contracts/__init__.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/contracts/agent_contracts.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/contracts/base_contracts.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/contracts/node_contracts.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/contracts/strict_contract.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/errors/__init__.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/errors/circuit_breaker.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/errors/error_handler.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/errors/exceptions.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/files.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/llm/__init__.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/llm/factory.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/llm/gateway.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/llm/openai_compatible.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/llm/protocol.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/llm/tokens.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/llm/tools.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/mcp.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/messaging/__init__.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/messaging/models.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/nodes/__init__.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/nodes/aggregator_config.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/nodes/aggregator_node.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/nodes/base_node.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/nodes/delegation_config.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/nodes/delegation_node.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/nodes/delegation_transport.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/nodes/function_node.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/nodes/llm_node_config.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/nodes/plan_executor.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/nodes/planner_node.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/nodes/planning_models.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/observability/__init__.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/observability/_log.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/observability/events.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/observability/tool_events.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/observability/trace_context.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/observability/tracing.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/py.typed +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/rabbitmq/__init__.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/rabbitmq/client.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/rabbitmq/config.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/rabbitmq/consumer.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/rabbitmq/delegation_transport.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/rabbitmq/publisher.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/rabbitmq/rpc_client.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/rabbitmq/types.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/routing/__init__.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/routing/router.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/routing/strategies.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/runner/__init__.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/runner/config.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/runner/runner.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/state/__init__.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/state/conversation_state.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/state/history.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/state/memory.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/tools.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/workflows/__init__.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/workflows/chat.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/workflows/null.py +0 -0
- {sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/workflows/streaming_chat.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "sofias-sdk-lite"
|
|
3
|
-
version = "0.4.
|
|
3
|
+
version = "0.4.1"
|
|
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"
|
|
@@ -68,6 +68,9 @@ markers = ["integration: requires a running RabbitMQ broker"]
|
|
|
68
68
|
line-length = 100
|
|
69
69
|
target-version = "py311"
|
|
70
70
|
|
|
71
|
+
[tool.ruff.lint]
|
|
72
|
+
extend-select = ["TC004"]
|
|
73
|
+
|
|
71
74
|
[tool.pyright]
|
|
72
75
|
include = ["src"]
|
|
73
76
|
typeCheckingMode = "strict"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "sofias-sdk-lite"
|
|
3
|
-
version = "0.4.
|
|
3
|
+
version = "0.4.1"
|
|
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"
|
|
@@ -75,6 +75,13 @@ markers = ["integration: requires a running RabbitMQ broker"]
|
|
|
75
75
|
line-length = 100
|
|
76
76
|
target-version = "py311"
|
|
77
77
|
|
|
78
|
+
[tool.ruff.lint]
|
|
79
|
+
# TC004 catches a name imported only under ``if TYPE_CHECKING:`` but used at
|
|
80
|
+
# runtime. That shipped in 0.4.0 as a NameError the moment a node executed a
|
|
81
|
+
# caller-owned tool (TKT-067). Neither pyright strict nor mypy flag it: to them
|
|
82
|
+
# the symbol exists. Ruff is the one checker that does.
|
|
83
|
+
extend-select = ["TC004"]
|
|
84
|
+
|
|
78
85
|
[tool.pyright]
|
|
79
86
|
include = ["src"]
|
|
80
87
|
typeCheckingMode = "strict"
|
|
@@ -600,6 +600,7 @@ class LLMNode(BaseNode):
|
|
|
600
600
|
base_prompt: str,
|
|
601
601
|
prompt: str,
|
|
602
602
|
runtime_vars: dict[str, Any],
|
|
603
|
+
input_data: dict[str, Any],
|
|
603
604
|
) -> tuple[int, list[ToolSpec] | None, str]:
|
|
604
605
|
"""Re-read the tools when the catalog changed mid-turn.
|
|
605
606
|
|
|
@@ -616,6 +617,7 @@ class LLMNode(BaseNode):
|
|
|
616
617
|
would duplicate the schemas inside the text.
|
|
617
618
|
prompt: Current prompt.
|
|
618
619
|
runtime_vars: Template variables for this turn.
|
|
620
|
+
input_data: The node's validated input for this turn.
|
|
619
621
|
|
|
620
622
|
Returns:
|
|
621
623
|
Updated ``(revision, specs, prompt)``, or the ones received when
|
|
@@ -635,14 +637,33 @@ class LLMNode(BaseNode):
|
|
|
635
637
|
return (
|
|
636
638
|
revision,
|
|
637
639
|
new_specs,
|
|
638
|
-
self._prompt_with_registry_tools(base_prompt, new_specs, runtime_vars),
|
|
640
|
+
self._prompt_with_registry_tools(base_prompt, new_specs, runtime_vars, input_data),
|
|
639
641
|
)
|
|
640
642
|
|
|
643
|
+
def _assemble_prompt(self, runtime_vars: dict[str, Any], input_data: dict[str, Any]) -> str:
|
|
644
|
+
"""Assemble this turn's prompt with the node's assembler.
|
|
645
|
+
|
|
646
|
+
``input_data`` only reaches an assembler we built ourselves. A
|
|
647
|
+
caller-supplied one was written against ``assemble(runtime_vars=...)``
|
|
648
|
+
and would reject the extra keyword, so it keeps the signature it knows.
|
|
649
|
+
|
|
650
|
+
Args:
|
|
651
|
+
runtime_vars: Template variables for this turn (settings + input).
|
|
652
|
+
input_data: The node's validated input on its own.
|
|
653
|
+
|
|
654
|
+
Returns:
|
|
655
|
+
The assembled prompt.
|
|
656
|
+
"""
|
|
657
|
+
if not self._owns_prompt_assembler:
|
|
658
|
+
return self._prompt_assembler.assemble(runtime_vars=runtime_vars)
|
|
659
|
+
return self._prompt_assembler.assemble(runtime_vars=runtime_vars, input_data=input_data)
|
|
660
|
+
|
|
641
661
|
def _prompt_with_registry_tools(
|
|
642
662
|
self,
|
|
643
663
|
prompt: str,
|
|
644
664
|
tool_specs: list[ToolSpec] | None,
|
|
645
665
|
runtime_vars: dict[str, Any],
|
|
666
|
+
input_data: dict[str, Any],
|
|
646
667
|
) -> str:
|
|
647
668
|
"""Re-assemble the prompt including the registry's tools.
|
|
648
669
|
|
|
@@ -656,6 +677,7 @@ class LLMNode(BaseNode):
|
|
|
656
677
|
prompt: Prompt already assembled with the node's assembler.
|
|
657
678
|
tool_specs: Static plus registry tools, or None.
|
|
658
679
|
runtime_vars: Template variables for this turn.
|
|
680
|
+
input_data: The node's validated input for this turn.
|
|
659
681
|
|
|
660
682
|
Returns:
|
|
661
683
|
The re-assembled prompt, or the one received when no rebuild applies.
|
|
@@ -671,7 +693,7 @@ class LLMNode(BaseNode):
|
|
|
671
693
|
output_contract=self._config.output_contract,
|
|
672
694
|
raw_text=self._raw_text_field is not None,
|
|
673
695
|
)
|
|
674
|
-
return assembler.assemble(runtime_vars=runtime_vars)
|
|
696
|
+
return assembler.assemble(runtime_vars=runtime_vars, input_data=input_data)
|
|
675
697
|
|
|
676
698
|
async def _execute_registry_tool(self, tool_call: ToolCall, tool_start: float) -> ToolResult:
|
|
677
699
|
"""Execute a tool call via the ToolRegistry.
|
|
@@ -779,6 +801,12 @@ class LLMNode(BaseNode):
|
|
|
779
801
|
if modified_input is not None:
|
|
780
802
|
tool_input = modified_input
|
|
781
803
|
|
|
804
|
+
# ToolContext is a TYPE_CHECKING-only name in this module, and this is
|
|
805
|
+
# the one place that BUILDS one instead of just annotating with it, so
|
|
806
|
+
# it needs the real import at runtime. Same local-import idiom already
|
|
807
|
+
# used for DelegationNode, FanOutStrategy and StreamingResponseWorkflow.
|
|
808
|
+
from sofias_sdk_lite.tools import ToolContext
|
|
809
|
+
|
|
782
810
|
# Execute the tool using BaseTool.execute() in a worker thread (async, non-blocking)
|
|
783
811
|
try:
|
|
784
812
|
context = ToolContext(
|
|
@@ -999,7 +1027,7 @@ class LLMNode(BaseNode):
|
|
|
999
1027
|
|
|
1000
1028
|
runtime_vars = self._get_runtime_vars()
|
|
1001
1029
|
runtime_vars.update(input_data)
|
|
1002
|
-
prompt = self.
|
|
1030
|
+
prompt = self._assemble_prompt(runtime_vars, input_data)
|
|
1003
1031
|
|
|
1004
1032
|
max_iterations = self._get_max_iterations()
|
|
1005
1033
|
parallel_tool_calls = self._get_parallel_tool_calls()
|
|
@@ -1007,7 +1035,7 @@ class LLMNode(BaseNode):
|
|
|
1007
1035
|
tool_catalog_revision = self._tool_catalog_revision()
|
|
1008
1036
|
|
|
1009
1037
|
base_prompt = prompt
|
|
1010
|
-
prompt = self._prompt_with_registry_tools(prompt, tool_specs, runtime_vars)
|
|
1038
|
+
prompt = self._prompt_with_registry_tools(prompt, tool_specs, runtime_vars, input_data)
|
|
1011
1039
|
|
|
1012
1040
|
history: list[tuple[LLMResponse, list[ToolResult]]] = []
|
|
1013
1041
|
iteration = 0
|
|
@@ -1019,7 +1047,7 @@ class LLMNode(BaseNode):
|
|
|
1019
1047
|
|
|
1020
1048
|
while iteration < max_iterations:
|
|
1021
1049
|
tool_catalog_revision, tool_specs, prompt = await self._refresh_tool_catalog(
|
|
1022
|
-
tool_catalog_revision, tool_specs, base_prompt, prompt, runtime_vars
|
|
1050
|
+
tool_catalog_revision, tool_specs, base_prompt, prompt, runtime_vars, input_data
|
|
1023
1051
|
)
|
|
1024
1052
|
|
|
1025
1053
|
if token_budget and history:
|
|
@@ -1493,7 +1521,7 @@ class LLMNode(BaseNode):
|
|
|
1493
1521
|
runtime_vars = self._get_runtime_vars()
|
|
1494
1522
|
# Include validated input in runtime vars for prompt templates
|
|
1495
1523
|
runtime_vars.update(input_data)
|
|
1496
|
-
prompt = self.
|
|
1524
|
+
prompt = self._assemble_prompt(runtime_vars, input_data)
|
|
1497
1525
|
|
|
1498
1526
|
# Tool loop
|
|
1499
1527
|
max_iterations = self._get_max_iterations()
|
|
@@ -1502,7 +1530,9 @@ class LLMNode(BaseNode):
|
|
|
1502
1530
|
tool_catalog_revision = self._tool_catalog_revision()
|
|
1503
1531
|
|
|
1504
1532
|
base_prompt = prompt
|
|
1505
|
-
prompt = self._prompt_with_registry_tools(
|
|
1533
|
+
prompt = self._prompt_with_registry_tools(
|
|
1534
|
+
prompt, tool_specs, runtime_vars, input_data
|
|
1535
|
+
)
|
|
1506
1536
|
|
|
1507
1537
|
history: list[tuple[LLMResponse, list[ToolResult]]] = []
|
|
1508
1538
|
iteration = 0
|
|
@@ -1525,7 +1555,12 @@ class LLMNode(BaseNode):
|
|
|
1525
1555
|
|
|
1526
1556
|
while iteration < max_iterations:
|
|
1527
1557
|
tool_catalog_revision, tool_specs, prompt = await self._refresh_tool_catalog(
|
|
1528
|
-
tool_catalog_revision,
|
|
1558
|
+
tool_catalog_revision,
|
|
1559
|
+
tool_specs,
|
|
1560
|
+
base_prompt,
|
|
1561
|
+
prompt,
|
|
1562
|
+
runtime_vars,
|
|
1563
|
+
input_data,
|
|
1529
1564
|
)
|
|
1530
1565
|
|
|
1531
1566
|
if token_budget and history:
|
{sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/nodes/prompt_assembler.py
RENAMED
|
@@ -13,6 +13,7 @@ from pathlib import Path
|
|
|
13
13
|
from typing import TYPE_CHECKING, Any
|
|
14
14
|
|
|
15
15
|
from sofias_sdk_lite.llm import ToolSpec
|
|
16
|
+
from sofias_sdk_lite.observability._log import get_logger
|
|
16
17
|
|
|
17
18
|
if TYPE_CHECKING:
|
|
18
19
|
from sofias_sdk_lite.contracts import StrictContract
|
|
@@ -21,6 +22,8 @@ if TYPE_CHECKING:
|
|
|
21
22
|
# Re-export so existing importers keep working
|
|
22
23
|
__all__ = ["PromptAssembler", "ToolSpec"]
|
|
23
24
|
|
|
25
|
+
logger = get_logger("nodes.prompt_assembler")
|
|
26
|
+
|
|
24
27
|
|
|
25
28
|
class PromptAssembler:
|
|
26
29
|
"""Assembles the final prompt for LLM calls.
|
|
@@ -230,7 +233,44 @@ class PromptAssembler:
|
|
|
230
233
|
"""
|
|
231
234
|
return ""
|
|
232
235
|
|
|
233
|
-
|
|
236
|
+
@staticmethod
|
|
237
|
+
def _keys_used_by_template(template: str, input_data: dict[str, Any]) -> list[str]:
|
|
238
|
+
"""Which input keys the template actually references as {placeholders}.
|
|
239
|
+
|
|
240
|
+
Args:
|
|
241
|
+
template: The fixed prompt, before variable resolution.
|
|
242
|
+
input_data: The node's validated input.
|
|
243
|
+
|
|
244
|
+
Returns:
|
|
245
|
+
The referenced keys, empty when the template ignores the input.
|
|
246
|
+
"""
|
|
247
|
+
return [key for key in input_data if "{" + key + "}" in template]
|
|
248
|
+
|
|
249
|
+
def _format_input_section(self, input_data: dict[str, Any]) -> str:
|
|
250
|
+
"""Format the node's input as its own section.
|
|
251
|
+
|
|
252
|
+
The input reaches the model ONLY through {placeholders} in the fixed
|
|
253
|
+
prompt: there is no separate "user message" channel. A node configured
|
|
254
|
+
without ``NodePromptConfig`` therefore sent the model the tool catalogue
|
|
255
|
+
and nothing else, dropping the user's message in silence (TKT-066).
|
|
256
|
+
|
|
257
|
+
Args:
|
|
258
|
+
input_data: The node's validated input.
|
|
259
|
+
|
|
260
|
+
Returns:
|
|
261
|
+
Formatted input section, or empty string when there is no input.
|
|
262
|
+
"""
|
|
263
|
+
if not input_data:
|
|
264
|
+
return ""
|
|
265
|
+
|
|
266
|
+
body = json.dumps(input_data, indent=2, ensure_ascii=False, default=str)
|
|
267
|
+
return f"## Input\n\n```json\n{body}\n```"
|
|
268
|
+
|
|
269
|
+
def assemble(
|
|
270
|
+
self,
|
|
271
|
+
runtime_vars: dict[str, Any] | None = None,
|
|
272
|
+
input_data: dict[str, Any] | None = None,
|
|
273
|
+
) -> str:
|
|
234
274
|
"""Assemble the final prompt.
|
|
235
275
|
|
|
236
276
|
Combines the fixed prompt with variable sections (tools, output format)
|
|
@@ -238,6 +278,11 @@ class PromptAssembler:
|
|
|
238
278
|
|
|
239
279
|
Args:
|
|
240
280
|
runtime_vars: Optional runtime variables for template resolution.
|
|
281
|
+
input_data: The node's validated input, when the caller can tell it
|
|
282
|
+
apart from ``runtime_vars`` (which also carries agent settings).
|
|
283
|
+
Used to render the input for a node that has no prompt template,
|
|
284
|
+
and to warn when a template ignores it. Optional, so a
|
|
285
|
+
caller-supplied assembler keeps working without it.
|
|
241
286
|
|
|
242
287
|
Returns:
|
|
243
288
|
The complete assembled prompt ready for LLM invocation.
|
|
@@ -264,5 +309,24 @@ class PromptAssembler:
|
|
|
264
309
|
if output_section:
|
|
265
310
|
sections.append(output_section)
|
|
266
311
|
|
|
312
|
+
if input_data:
|
|
313
|
+
if not fixed_prompt:
|
|
314
|
+
# No template at all: without this the input never reaches the
|
|
315
|
+
# model. Appended last, after the tool schemas, so the task sits
|
|
316
|
+
# closest to where the model answers.
|
|
317
|
+
input_section = self._format_input_section(input_data)
|
|
318
|
+
if input_section:
|
|
319
|
+
sections.append(input_section)
|
|
320
|
+
elif not self._keys_used_by_template(fixed_prompt, input_data):
|
|
321
|
+
# A template that names none of the input keys drops the input
|
|
322
|
+
# just as silently, but it may be deliberate (a node whose input
|
|
323
|
+
# only passes through to the output), so this only warns.
|
|
324
|
+
logger.warning(
|
|
325
|
+
"Prompt template references none of the node's input: the "
|
|
326
|
+
"model will not see it. Reference it as {placeholder}.",
|
|
327
|
+
node_name=self._config.name,
|
|
328
|
+
input_keys=sorted(input_data),
|
|
329
|
+
)
|
|
330
|
+
|
|
267
331
|
# Join sections with clear separation
|
|
268
332
|
return "\n\n".join(sections).strip()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/agent/execution_context.py
RENAMED
|
File without changes
|
|
File without changes
|
{sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/agent/response_workflow.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/config/agent_settings.py
RENAMED
|
File without changes
|
|
File without changes
|
{sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/config/runtime_config.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/contracts/agent_contracts.py
RENAMED
|
File without changes
|
{sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/contracts/base_contracts.py
RENAMED
|
File without changes
|
{sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/contracts/node_contracts.py
RENAMED
|
File without changes
|
{sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/contracts/strict_contract.py
RENAMED
|
File without changes
|
|
File without changes
|
{sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/errors/circuit_breaker.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/llm/openai_compatible.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/nodes/aggregator_config.py
RENAMED
|
File without changes
|
{sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/nodes/aggregator_node.py
RENAMED
|
File without changes
|
|
File without changes
|
{sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/nodes/delegation_config.py
RENAMED
|
File without changes
|
{sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/nodes/delegation_node.py
RENAMED
|
File without changes
|
{sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/nodes/delegation_transport.py
RENAMED
|
File without changes
|
|
File without changes
|
{sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/nodes/llm_node_config.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/nodes/planning_models.py
RENAMED
|
File without changes
|
{sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/observability/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/observability/tool_events.py
RENAMED
|
File without changes
|
{sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/observability/trace_context.py
RENAMED
|
File without changes
|
{sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/observability/tracing.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/rabbitmq/delegation_transport.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/state/conversation_state.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sofias_sdk_lite-0.4.0 → sofias_sdk_lite-0.4.1}/src/sofias_sdk_lite/workflows/streaming_chat.py
RENAMED
|
File without changes
|