jaf-py 2.5.13__py3-none-any.whl → 2.6.1__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.
jaf/__init__.py CHANGED
@@ -201,7 +201,7 @@ def generate_run_id() -> RunId:
201
201
  return create_run_id(str(uuid.uuid4()))
202
202
 
203
203
 
204
- __version__ = "2.5.13"
204
+ __version__ = "2.6.1"
205
205
  __all__ = [
206
206
  # Core types and functions
207
207
  "TraceId",
jaf/core/tools.py CHANGED
@@ -224,38 +224,18 @@ def create_async_function_tool_legacy(
224
224
 
225
225
 
226
226
  def _extract_docstring_info(func):
227
- """Extract description and parameter info from function docstring."""
227
+ """Extract description from function docstring.
228
+
229
+ Returns the entire docstring as the description since parameters are
230
+ extracted from the function signature, not the docstring.
231
+ """
228
232
  doc = inspect.getdoc(func)
229
233
  if not doc:
230
234
  return func.__name__.replace("_", " ").title(), {}
231
235
 
232
- lines = doc.strip().split("\n")
233
- if not lines:
234
- return func.__name__.replace("_", " ").title(), {}
235
-
236
- # First non-empty line is the description
237
- description = lines[0].strip()
238
-
239
- # Look for Args section to extract parameter descriptions
240
- param_descriptions = {}
241
- in_args_section = False
242
-
243
- for line in lines[1:]:
244
- line = line.strip()
245
- if line.lower().startswith("args:"):
246
- in_args_section = True
247
- continue
248
- elif line.lower().startswith(
249
- ("returns:", "return:", "raises:", "raise:", "examples:", "example:")
250
- ):
251
- in_args_section = False
252
- continue
253
- elif in_args_section and line and ":" in line:
254
- # Parse parameter description like "location: The location to fetch the weather for."
255
- param_name, param_desc = line.split(":", 1)
256
- param_descriptions[param_name.strip()] = param_desc.strip()
257
-
258
- return description, param_descriptions
236
+ # Return the entire docstring as description
237
+ # param_descriptions is kept for backward compatibility but is not used
238
+ return doc.strip(), {}
259
239
 
260
240
 
261
241
  def _create_parameter_schema_from_signature(func):
jaf/core/tracing.py CHANGED
@@ -407,6 +407,7 @@ class LangfuseTraceCollector:
407
407
  httpx_client: Optional[httpx.Client] = None,
408
408
  proxy: Optional[str] = None,
409
409
  timeout: Optional[int] = None,
410
+ include_system_prompt: bool = False,
410
411
  ):
411
412
  """Initialize Langfuse trace collector.
412
413
 
@@ -417,6 +418,7 @@ class LangfuseTraceCollector:
417
418
  Only used if httpx_client is not provided.
418
419
  Falls back to LANGFUSE_PROXY environment variable.
419
420
  timeout: Optional timeout in seconds for HTTP requests. Defaults to 10.
421
+ include_system_prompt: Whether to include system prompt in trace metadata. Defaults to False.
420
422
  """
421
423
  public_key = os.environ.get("LANGFUSE_PUBLIC_KEY")
422
424
  secret_key = os.environ.get("LANGFUSE_SECRET_KEY")
@@ -467,10 +469,11 @@ class LangfuseTraceCollector:
467
469
  public_key=public_key,
468
470
  secret_key=secret_key,
469
471
  host=host,
470
- release="jaf-py-v2.5.13",
472
+ release="jaf-py-v2.6.1",
471
473
  httpx_client=client,
472
474
  )
473
475
  self._httpx_client = client
476
+ self.include_system_prompt = include_system_prompt
474
477
 
475
478
  # Detect Langfuse version (v2 has trace() method, v3 does not)
476
479
  self._is_langfuse_v3 = not hasattr(self.langfuse, "trace")
@@ -741,6 +744,17 @@ class LangfuseTraceCollector:
741
744
  f"[LANGFUSE DEBUG] Added to conversation history: role={role}, content_length={len(str(content))}, has_tool_calls={bool(msg_data.get('tool_calls'))}"
742
745
  )
743
746
 
747
+ # Extract system prompt from context if enabled
748
+ system_prompt = None
749
+ if self.include_system_prompt and context:
750
+ if isinstance(context, dict):
751
+ system_prompt = context.get("system_prompt")
752
+ elif hasattr(context, "system_prompt"):
753
+ system_prompt = context.system_prompt
754
+
755
+ if system_prompt:
756
+ print(f"[LANGFUSE DEBUG] Extracted system_prompt: {system_prompt[:100] if isinstance(system_prompt, str) else system_prompt}...")
757
+
744
758
  print(
745
759
  f"[LANGFUSE DEBUG] Final extracted - user_query: {user_query}, user_id: {user_id}"
746
760
  )
@@ -778,6 +792,27 @@ class LangfuseTraceCollector:
778
792
  # Extract agent_name for tagging
779
793
  agent_name = self._get_event_data(event, "agent_name") or "analytics_agent_jaf"
780
794
 
795
+ # Build metadata with optional system_prompt
796
+ metadata = {
797
+ "framework": "jaf",
798
+ "event_type": "run_start",
799
+ "trace_id": str(trace_id),
800
+ "user_query": user_query,
801
+ "user_id": user_id or self._get_event_data(event, "user_id"),
802
+ "agent_name": agent_name,
803
+ "conversation_history": conversation_history,
804
+ "tool_calls": [],
805
+ "tool_results": [],
806
+ "user_info": self._get_event_data(event, "context").user_info
807
+ if self._get_event_data(event, "context")
808
+ and hasattr(self._get_event_data(event, "context"), "user_info")
809
+ else None,
810
+ }
811
+
812
+ # Add system_prompt to metadata if enabled and available
813
+ if self.include_system_prompt and system_prompt:
814
+ metadata["system_prompt"] = system_prompt
815
+
781
816
  # Use compatibility layer to create trace (works with both v2 and v3)
782
817
  trace = self._create_trace(
783
818
  trace_id=trace_id,
@@ -786,27 +821,15 @@ class LangfuseTraceCollector:
786
821
  session_id=self._get_event_data(event, "session_id"),
787
822
  input=trace_input,
788
823
  tags=[agent_name], # Add agent_name as a tag for dashboard filtering
789
- metadata={
790
- "framework": "jaf",
791
- "event_type": "run_start",
792
- "trace_id": str(trace_id),
793
- "user_query": user_query,
794
- "user_id": user_id or self._get_event_data(event, "user_id"),
795
- "agent_name": agent_name,
796
- "conversation_history": conversation_history,
797
- "tool_calls": [],
798
- "tool_results": [],
799
- "user_info": self._get_event_data(event, "context").user_info
800
- if self._get_event_data(event, "context")
801
- and hasattr(self._get_event_data(event, "context"), "user_info")
802
- else None,
803
- },
824
+ metadata=metadata,
804
825
  )
805
826
  self.trace_spans[trace_id] = trace
806
- # Store user_id, user_query, and conversation_history for later use
827
+ # Store user_id, user_query, conversation_history, and system_prompt for later use
807
828
  trace._user_id = user_id or self._get_event_data(event, "user_id")
808
829
  trace._user_query = user_query
809
830
  trace._conversation_history = conversation_history
831
+ if self.include_system_prompt:
832
+ trace._system_prompt = system_prompt
810
833
  print(
811
834
  f"[LANGFUSE] Created trace with user query: {user_query[:100] if user_query else 'None'}..."
812
835
  )
@@ -833,6 +856,12 @@ class LangfuseTraceCollector:
833
856
  "tool_results": self.trace_tool_results.get(trace_id, []),
834
857
  }
835
858
 
859
+ # Add system_prompt to final metadata if enabled and available
860
+ if self.include_system_prompt:
861
+ system_prompt = getattr(self.trace_spans[trace_id], "_system_prompt", None)
862
+ if system_prompt:
863
+ final_metadata["system_prompt"] = system_prompt
864
+
836
865
  # End the trace with updated metadata
837
866
  self.trace_spans[trace_id].update(output=event.data, metadata=final_metadata)
838
867
 
@@ -1198,6 +1227,7 @@ def create_composite_trace_collector(
1198
1227
  otel_session: Optional[Any] = None,
1199
1228
  proxy: Optional[str] = None,
1200
1229
  timeout: Optional[int] = None,
1230
+ include_system_prompt: bool = False,
1201
1231
  ) -> TraceCollector:
1202
1232
  """Create a composite trace collector that forwards events to multiple collectors.
1203
1233
 
@@ -1213,6 +1243,7 @@ def create_composite_trace_collector(
1213
1243
  If not set, both respect standard HTTP_PROXY/HTTPS_PROXY environment variables.
1214
1244
  timeout: Optional timeout in seconds for HTTP requests (applies to both Langfuse and OTEL).
1215
1245
  For Langfuse: Falls back to LANGFUSE_TIMEOUT environment variable (default: 10).
1246
+ include_system_prompt: Whether to include system prompt in Langfuse trace metadata. Defaults to False.
1216
1247
  """
1217
1248
  collector_list = list(collectors)
1218
1249
 
@@ -1229,7 +1260,7 @@ def create_composite_trace_collector(
1229
1260
  # Automatically add Langfuse collector if keys are configured
1230
1261
  if os.getenv("LANGFUSE_PUBLIC_KEY") and os.getenv("LANGFUSE_SECRET_KEY"):
1231
1262
  langfuse_collector = LangfuseTraceCollector(
1232
- httpx_client=httpx_client, proxy=proxy, timeout=timeout
1263
+ httpx_client=httpx_client, proxy=proxy, timeout=timeout, include_system_prompt=include_system_prompt
1233
1264
  )
1234
1265
  collector_list.append(langfuse_collector)
1235
1266
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: jaf-py
3
- Version: 2.5.13
3
+ Version: 2.6.1
4
4
  Summary: A purely functional agent framework with immutable state and composable tools - Python implementation
5
5
  Author: JAF Contributors
6
6
  Maintainer: JAF Contributors
@@ -82,7 +82,7 @@ Dynamic: license-file
82
82
 
83
83
  <!-- ![JAF Banner](docs/cover.png) -->
84
84
 
85
- [![Version](https://img.shields.io/badge/version-2.5.13-blue.svg)](https://github.com/xynehq/jaf-py)
85
+ [![Version](https://img.shields.io/badge/version-2.6.1-blue.svg)](https://github.com/xynehq/jaf-py)
86
86
  [![Python](https://img.shields.io/badge/python-3.10%2B-blue.svg)](https://www.python.org/)
87
87
  [![Docs](https://img.shields.io/badge/Docs-Live-brightgreen)](https://xynehq.github.io/jaf-py/)
88
88
 
@@ -1,4 +1,4 @@
1
- jaf/__init__.py,sha256=O4KeBTYc6q85QK9XWllFHmMRdIdnvToftYSR5L8Mljk,8653
1
+ jaf/__init__.py,sha256=sFcfeb0oKFTS3TfOhCxV0-UnpRwvA1AAcvdD6_I_zPM,8652
2
2
  jaf/cli.py,sha256=EDMMA5uX0e3TUIedLdyP3p4Qy-aXADvpht3VgJPJagU,8299
3
3
  jaf/exceptions.py,sha256=FdLIw7bdCNtBYfqRyJBkRT4Z1vWuvkzrMqFiMAzjL8Y,9158
4
4
  jaf/a2a/__init__.py,sha256=r4W-WHZNjoxR8EQ0x41_rY3fl12OH5qcSn0KycXaKKU,7752
@@ -55,8 +55,8 @@ jaf/core/regeneration.py,sha256=TUoBs4xZtFt3xBGA0N9cMsprtRL9BdmJeX5OnyLyGiE,1916
55
55
  jaf/core/state.py,sha256=fdWDc2DQ-o_g_8E4ibg2QM0Vad_XUique3a5iYBwGZo,9516
56
56
  jaf/core/streaming.py,sha256=5ntOtJrZVCHuGsygquyCLG2J5yuSxE6DN5OM-BrQiGw,16818
57
57
  jaf/core/tool_results.py,sha256=L9U3JDQAjAH5YR7iMpSxfVky2Nxo6FYQs4WE05RATaQ,11283
58
- jaf/core/tools.py,sha256=qsnC1Deo1VXpheUuRox26PrrfUoOJ-ZvxkiXzko5lVQ,15856
59
- jaf/core/tracing.py,sha256=GL-BXEZKDRHqDHICSPWbTPoRIl014DEsSfp-LvCUnNw,55604
58
+ jaf/core/tools.py,sha256=rHxzAfGVGpYk3YJKmrq3AQLW0oE3ACkiJBOwle2bLdc,15146
59
+ jaf/core/tracing.py,sha256=dPX1aHBk-auHcgMHttOZjLdo7aqB6GXmFLoGb3_bSoo,57320
60
60
  jaf/core/types.py,sha256=1QolTM3IYnQArbYAZkCIfj868j9vyEZTThqw37q7EyU,35395
61
61
  jaf/core/workflows.py,sha256=0825AoD1QwEiGAs5IRlWHmaKrjurx6xF7oDJR6POBsg,25651
62
62
  jaf/memory/__init__.py,sha256=YfANOg5vUFSPVG7gpBE4_lYkV5X3_U6Yj9v1_QexfN0,1396
@@ -89,9 +89,9 @@ jaf/visualization/functional_core.py,sha256=0Xs2R8ELADKNIgokcbjuxmWwxEyCH1yXIEdG
89
89
  jaf/visualization/graphviz.py,sha256=EwWVIRv8Z7gTiO5Spvcm-z_UUQ1oWNPRgdE33ZzFwx8,11569
90
90
  jaf/visualization/imperative_shell.py,sha256=N5lWzOLMIU_iCoy3n5WCg49eec8VxV8f7JIG6_wNtVw,2506
91
91
  jaf/visualization/types.py,sha256=90G8oClsFa_APqTuMrTW6KjD0oG9I4kVur773dXNW0E,1393
92
- jaf_py-2.5.13.dist-info/licenses/LICENSE,sha256=LXUQBJxdyr-7C4bk9cQBwvsF_xwA-UVstDTKabpcjlI,1063
93
- jaf_py-2.5.13.dist-info/METADATA,sha256=i8bgFJtK7JNOiadUK6w4LmBeR3L0wI4kMz1sDj-FgUY,27745
94
- jaf_py-2.5.13.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
95
- jaf_py-2.5.13.dist-info/entry_points.txt,sha256=OtIJeNJpb24kgGrqRx9szGgDx1vL9ayq8uHErmu7U5w,41
96
- jaf_py-2.5.13.dist-info/top_level.txt,sha256=Xu1RZbGaM4_yQX7bpalo881hg7N_dybaOW282F15ruE,4
97
- jaf_py-2.5.13.dist-info/RECORD,,
92
+ jaf_py-2.6.1.dist-info/licenses/LICENSE,sha256=LXUQBJxdyr-7C4bk9cQBwvsF_xwA-UVstDTKabpcjlI,1063
93
+ jaf_py-2.6.1.dist-info/METADATA,sha256=_tsvDUvHWYLcfhzn2CFTGlIIn-XvLpUMiF4NaxCqCKI,27743
94
+ jaf_py-2.6.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
95
+ jaf_py-2.6.1.dist-info/entry_points.txt,sha256=OtIJeNJpb24kgGrqRx9szGgDx1vL9ayq8uHErmu7U5w,41
96
+ jaf_py-2.6.1.dist-info/top_level.txt,sha256=Xu1RZbGaM4_yQX7bpalo881hg7N_dybaOW282F15ruE,4
97
+ jaf_py-2.6.1.dist-info/RECORD,,