fastworkflow 2.17.5__py3-none-any.whl → 2.17.6__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of fastworkflow might be problematic. Click here for more details.

@@ -467,15 +467,28 @@ class ChatSession:
467
467
  self
468
468
  )
469
469
 
470
+ # Get available commands for current context and pass to agent.
471
+ # The CommandsSystemPreludeAdapter will inject these commands into the system
472
+ # message, keeping them out of the trajectory to avoid token bloat while still
473
+ # providing context-specific command info.
474
+ from fastworkflow.workflow_agent import _what_can_i_do
475
+ available_commands = _what_can_i_do(self)
476
+
470
477
  lm = dspy_utils.get_lm("LLM_AGENT", "LITELLM_API_KEY_AGENT")
471
478
  from dspy.utils.exceptions import AdapterParseError
479
+ from fastworkflow.utils.chat_adapter import CommandsSystemPreludeAdapter
480
+
481
+ # Use CommandsSystemPreludeAdapter specifically for workflow agent calls
482
+ agent_adapter = CommandsSystemPreludeAdapter()
483
+
472
484
  # Retry logic for AdapterParseError
473
485
  max_retries = 2
474
486
  for attempt in range(max_retries):
475
487
  try:
476
- with dspy.context(lm=lm, adapter=dspy.ChatAdapter()):
488
+ with dspy.context(lm=lm, adapter=agent_adapter):
477
489
  agent_result = self._workflow_tool_agent(
478
- user_query=command_info_and_refined_message_with_todolist
490
+ user_query=command_info_and_refined_message_with_todolist,
491
+ available_commands=available_commands
479
492
  )
480
493
  break # Success, exit retry loop
481
494
  except AdapterParseError as _:
@@ -0,0 +1,99 @@
1
+ """
2
+ ChatAdapter wrapper for injecting context-specific available commands into system messages.
3
+
4
+ Design Overview:
5
+ ---------------
6
+ This module implements a ChatAdapter wrapper that dynamically injects workflow command information
7
+ into the system message at runtime, avoiding the need to rebuild ReAct agent modules per context.
8
+
9
+ Key Benefits:
10
+ - Single shared agent: No per-context module caching required
11
+ - Dynamic updates: Commands refresh per call based on current workflow context
12
+ - Token efficiency: Commands appear in system (not repeated in trajectory/history)
13
+ - Zero rebuild cost: Signature and modules remain stable across context changes
14
+
15
+ Usage:
16
+ ------
17
+ The adapter is used specifically for workflow agent calls via dspy.context():
18
+
19
+ from fastworkflow.utils.chat_adapter import CommandsSystemPreludeAdapter
20
+
21
+ agent_adapter = CommandsSystemPreludeAdapter()
22
+ available_commands = _what_can_i_do(chat_session)
23
+
24
+ with dspy.context(lm=lm, adapter=agent_adapter):
25
+ agent_result = agent(
26
+ user_query="...",
27
+ available_commands=available_commands
28
+ )
29
+
30
+ The adapter intercepts the format call and prepends commands to the system message,
31
+ keeping them out of the trajectory to prevent token bloat across iterations.
32
+ This scoped approach ensures the adapter only affects workflow agent calls, not other
33
+ DSPy operations in the system.
34
+ """
35
+ import dspy
36
+
37
+
38
+ class CommandsSystemPreludeAdapter(dspy.ChatAdapter):
39
+ """
40
+ Wraps a base DSPy ChatAdapter to inject available commands into the system message.
41
+
42
+ This adapter intercepts the render process and prepends a "Available commands" section
43
+ to the system message when `available_commands` is present in inputs. This ensures
44
+ commands are visible to the model at each step without being added to the trajectory
45
+ or conversation history.
46
+
47
+ Args:
48
+ base: The underlying ChatAdapter to wrap. Defaults to dspy.ChatAdapter() if None.
49
+ title: The header text for the commands section. Defaults to "Available commands".
50
+
51
+ Example:
52
+ >>> import dspy
53
+ >>> from fastworkflow.utils.chat_adapter import CommandsSystemPreludeAdapter
54
+ >>> dspy.settings.adapter = CommandsSystemPreludeAdapter()
55
+ """
56
+
57
+ def __init__(self, base: dspy.ChatAdapter | None = None, title: str = "Available commands"):
58
+ super().__init__()
59
+ self.base = base or dspy.ChatAdapter()
60
+ self.title = title
61
+
62
+ def format(self, signature, demos, inputs):
63
+ """
64
+ Format the inputs for the model, injecting available_commands into system message.
65
+
66
+ This method wraps the base adapter's format method and modifies the result
67
+ to include available commands in the system message if present in inputs.
68
+
69
+ Args:
70
+ signature: The DSPy signature defining the task
71
+ demos: List of demonstration examples
72
+ inputs: Dictionary of input values, may include 'available_commands'
73
+
74
+ Returns:
75
+ Formatted messages with commands injected into system message
76
+ """
77
+ # Call the base adapter's format method
78
+ formatted = self.base.format(signature, demos, inputs)
79
+
80
+ # Check if available_commands is in inputs
81
+ cmds = inputs.get("available_commands")
82
+ if not cmds:
83
+ return formatted
84
+
85
+ # Inject commands into the system message
86
+ prelude = f"{self.title}:\n{cmds}".strip()
87
+
88
+ # Formatted output is a list of messages, first may be system
89
+ # Find and modify the system message, or prepend one
90
+ if formatted and formatted[0].get("role") == "system":
91
+ # Prepend to existing system message
92
+ existing_content = formatted[0].get("content", "")
93
+ formatted[0]["content"] = f"{prelude}\n\n{existing_content}".strip()
94
+ else:
95
+ # No system message exists, prepend one
96
+ formatted.insert(0, {"role": "system", "content": prelude})
97
+
98
+ return formatted
99
+
@@ -67,13 +67,17 @@ class fastWorkflowReAct(Module):
67
67
  args={},
68
68
  )
69
69
 
70
- for idx, tool in enumerate(tools.values()):
71
- instr.append(f"({idx + 1}) {tool}")
70
+ instr.extend(f"({idx + 1}) {tool}" for idx, tool in enumerate(tools.values()))
72
71
  instr.append("When providing `next_tool_args`, the value inside the field must be in JSON format")
73
72
 
73
+ # Build the ReAct signature with trajectory and available_commands inputs.
74
+ # available_commands is injected into system message by CommandsSystemPreludeAdapter
75
+ # (see fastworkflow/utils/chat_adapter.py) and is NOT included in the trajectory
76
+ # formatting to avoid token bloat across iterations.
74
77
  react_signature = (
75
78
  dspy.Signature({**signature.input_fields}, "\n".join(instr))
76
79
  .append("trajectory", dspy.InputField(), type_=str)
80
+ .append("available_commands", dspy.InputField(), type_=str)
77
81
  .append("next_thought", dspy.OutputField(), type_=str)
78
82
  .append("next_tool_name", dspy.OutputField(), type_=Literal[tuple(tools.keys())])
79
83
  .append("next_tool_args", dspy.OutputField(), type_=dict[str, Any])
@@ -82,7 +86,7 @@ class fastWorkflowReAct(Module):
82
86
  fallback_signature = dspy.Signature(
83
87
  {**signature.input_fields, **signature.output_fields},
84
88
  signature.instructions,
85
- ).append("trajectory", dspy.InputField(), type_=str)
89
+ ).append("trajectory", dspy.InputField(), type_=str).append("available_commands", dspy.InputField(), type_=str)
86
90
 
87
91
  self.tools = tools
88
92
  self.react = dspy.Predict(react_signature)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fastworkflow
3
- Version: 2.17.5
3
+ Version: 2.17.6
4
4
  Summary: A framework for rapidly building large-scale, deterministic, interactive workflows with a fault-tolerant, conversational UX
5
5
  License: Apache-2.0
6
6
  Keywords: fastworkflow,ai,workflow,llm,openai
@@ -35,7 +35,7 @@ fastworkflow/build/navigator_stub_generator.py,sha256=_DSvHC6r1xWQiFHtUgPhI51nQf
35
35
  fastworkflow/build/pydantic_model_generator.py,sha256=oNyoANyUWBpHG-fE3tGL911RNvDzQXjxAm0ssvuXUH4,1854
36
36
  fastworkflow/build/utterance_generator.py,sha256=UrtkF0wyAZ1hiFitHX0g8w7Wh-D0leLCrP1aUACSfHo,299
37
37
  fastworkflow/cache_matching.py,sha256=OoB--1tO6-O4BKCuCrUbB0CkUr76J62K4VAf6MShi-w,7984
38
- fastworkflow/chat_session.py,sha256=mduwtY27MV5YcabUbaFDXyRalVVNLUpp7ZFNiOV9ewc,31627
38
+ fastworkflow/chat_session.py,sha256=u3aQauea5vYmt98_ADTkWzkF_WsJaaiA8AX6OlGeyf8,32332
39
39
  fastworkflow/cli.py,sha256=n-PFDC0EOkq1zIK1Ip44at-VcaP9cW9aSxZ2IVj3VoE,23796
40
40
  fastworkflow/command_context_model.py,sha256=bQadDB_IH2lc0br46IT07Iej_j2KrAMderiVKqU7gno,15914
41
41
  fastworkflow/command_directory.py,sha256=aJ6UQCwevfF11KbcQB2Qz6mQ7Kj91pZtvHmQY6JFnao,29030
@@ -158,6 +158,7 @@ fastworkflow/train/__main__.py,sha256=AeGja42d0QhslQkxvDVigIluxxL7DYLdQPXYFOKQ7Q
158
158
  fastworkflow/train/generate_synthetic.py,sha256=sTDk-E5ewkS4o-0LJeofiEv4uXGpqdGcFRYKY_Yf36Y,5322
159
159
  fastworkflow/user_message_queues.py,sha256=svbuFxQ16q6Tz6urPWfD4IEsOTMxtS1Kc1PP8EE8AWg,1422
160
160
  fastworkflow/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
161
+ fastworkflow/utils/chat_adapter.py,sha256=ujJaq0eGT1EvgDXUOZFVMuLrwhOzawi0LXsengN1DdM,4062
161
162
  fastworkflow/utils/command_dependency_graph.py,sha256=7YmAnVXcaLsPVeC3SvM4pGdUsCUxWM4H2qXrtGwQpAI,13512
162
163
  fastworkflow/utils/context_utils.py,sha256=mjYVzNJCmimNMmBdOKfzFeDSws_oAADAwcfz_N6sR7M,749
163
164
  fastworkflow/utils/dspy_cache_utils.py,sha256=OP2IsWPMGCdhjC-4iRqggWgTEfvPxFN_78tV1_C6uHY,3725
@@ -170,14 +171,14 @@ fastworkflow/utils/logging.py,sha256=2SA-04fg7Lx_vGf980tfCOGDQxBvU9X6Vbhv47rbdaw
170
171
  fastworkflow/utils/parameterize_func_decorator.py,sha256=V6YJnishWRCdwiBQW6P17hmGGrga0Empk-AN5Gm7iMk,633
171
172
  fastworkflow/utils/pydantic_model_2_dspy_signature_class.py,sha256=w1pvl8rJq48ulFwaAtBgfXYn_SBIDBgq1aLMUg1zJn8,12875
172
173
  fastworkflow/utils/python_utils.py,sha256=D0JBdzkwKoyK7XvZcnIxOgsS8CRGdvuW-zcO45_pfOA,8252
173
- fastworkflow/utils/react.py,sha256=HubwmM4H9UzLaLaeIkJseKCNMjyrOXvMZz-8sw4ycCE,11224
174
+ fastworkflow/utils/react.py,sha256=2nsmtwFZJ9QkZqNxDt94a1cpuFSZplTTYeH-Z2dEX5s,11668
174
175
  fastworkflow/utils/signatures.py,sha256=QOLX3j-AJkRWIkDhogbhxQo8MIt668xIKwd4SWiS2LY,31734
175
176
  fastworkflow/utils/startup_progress.py,sha256=9icSdnpFAxzIq0sUliGpNaH0Efvrt5lDtGfURV5BD98,3539
176
177
  fastworkflow/workflow.py,sha256=37gn7e3ct-gdGw43zS6Ab_ADoJJBO4eJW2PywfUpjEg,18825
177
178
  fastworkflow/workflow_agent.py,sha256=-RXoHXH-vrEh6AWC6iYAwwR9CvaRynYuu-KrzOPCJbg,16348
178
179
  fastworkflow/workflow_inheritance_model.py,sha256=Pp-qSrQISgPfPjJVUfW84pc7HLmL2evuq0UVIYR51K0,7974
179
- fastworkflow-2.17.5.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
180
- fastworkflow-2.17.5.dist-info/METADATA,sha256=ZQS_0wRF3-QBbTIhRwwHzpTgeDHzz2gxBogyK0JLX7Q,30634
181
- fastworkflow-2.17.5.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
182
- fastworkflow-2.17.5.dist-info/entry_points.txt,sha256=m8HqoPzCyaZLAx-V5X8MJgw3Lx3GiPDlxNEZ7K-Gb-U,54
183
- fastworkflow-2.17.5.dist-info/RECORD,,
180
+ fastworkflow-2.17.6.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
181
+ fastworkflow-2.17.6.dist-info/METADATA,sha256=u9UC1o2IBRPhTWO6a8fHxkRz1swR19md9xeIrc6gmwQ,30634
182
+ fastworkflow-2.17.6.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
183
+ fastworkflow-2.17.6.dist-info/entry_points.txt,sha256=m8HqoPzCyaZLAx-V5X8MJgw3Lx3GiPDlxNEZ7K-Gb-U,54
184
+ fastworkflow-2.17.6.dist-info/RECORD,,