jaf-py 2.5.10__py3-none-any.whl → 2.5.11__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.
Files changed (92) hide show
  1. jaf/__init__.py +154 -57
  2. jaf/a2a/__init__.py +42 -21
  3. jaf/a2a/agent.py +79 -126
  4. jaf/a2a/agent_card.py +87 -78
  5. jaf/a2a/client.py +30 -66
  6. jaf/a2a/examples/client_example.py +12 -12
  7. jaf/a2a/examples/integration_example.py +38 -47
  8. jaf/a2a/examples/server_example.py +56 -53
  9. jaf/a2a/memory/__init__.py +0 -4
  10. jaf/a2a/memory/cleanup.py +28 -21
  11. jaf/a2a/memory/factory.py +155 -133
  12. jaf/a2a/memory/providers/composite.py +21 -26
  13. jaf/a2a/memory/providers/in_memory.py +89 -83
  14. jaf/a2a/memory/providers/postgres.py +117 -115
  15. jaf/a2a/memory/providers/redis.py +128 -121
  16. jaf/a2a/memory/serialization.py +77 -87
  17. jaf/a2a/memory/tests/run_comprehensive_tests.py +112 -83
  18. jaf/a2a/memory/tests/test_cleanup.py +211 -94
  19. jaf/a2a/memory/tests/test_serialization.py +73 -68
  20. jaf/a2a/memory/tests/test_stress_concurrency.py +186 -133
  21. jaf/a2a/memory/tests/test_task_lifecycle.py +138 -120
  22. jaf/a2a/memory/types.py +91 -53
  23. jaf/a2a/protocol.py +95 -125
  24. jaf/a2a/server.py +90 -118
  25. jaf/a2a/standalone_client.py +30 -43
  26. jaf/a2a/tests/__init__.py +16 -33
  27. jaf/a2a/tests/run_tests.py +17 -53
  28. jaf/a2a/tests/test_agent.py +40 -140
  29. jaf/a2a/tests/test_client.py +54 -117
  30. jaf/a2a/tests/test_integration.py +28 -82
  31. jaf/a2a/tests/test_protocol.py +54 -139
  32. jaf/a2a/tests/test_types.py +50 -136
  33. jaf/a2a/types.py +58 -34
  34. jaf/cli.py +21 -41
  35. jaf/core/__init__.py +7 -1
  36. jaf/core/agent_tool.py +93 -72
  37. jaf/core/analytics.py +257 -207
  38. jaf/core/checkpoint.py +223 -0
  39. jaf/core/composition.py +249 -235
  40. jaf/core/engine.py +817 -519
  41. jaf/core/errors.py +55 -42
  42. jaf/core/guardrails.py +276 -202
  43. jaf/core/handoff.py +47 -31
  44. jaf/core/parallel_agents.py +69 -75
  45. jaf/core/performance.py +75 -73
  46. jaf/core/proxy.py +43 -44
  47. jaf/core/proxy_helpers.py +24 -27
  48. jaf/core/regeneration.py +220 -129
  49. jaf/core/state.py +68 -66
  50. jaf/core/streaming.py +115 -108
  51. jaf/core/tool_results.py +111 -101
  52. jaf/core/tools.py +114 -116
  53. jaf/core/tracing.py +269 -210
  54. jaf/core/types.py +371 -151
  55. jaf/core/workflows.py +209 -168
  56. jaf/exceptions.py +46 -38
  57. jaf/memory/__init__.py +1 -6
  58. jaf/memory/approval_storage.py +54 -77
  59. jaf/memory/factory.py +4 -4
  60. jaf/memory/providers/in_memory.py +216 -180
  61. jaf/memory/providers/postgres.py +216 -146
  62. jaf/memory/providers/redis.py +173 -116
  63. jaf/memory/types.py +70 -51
  64. jaf/memory/utils.py +36 -34
  65. jaf/plugins/__init__.py +12 -12
  66. jaf/plugins/base.py +105 -96
  67. jaf/policies/__init__.py +0 -1
  68. jaf/policies/handoff.py +37 -46
  69. jaf/policies/validation.py +76 -52
  70. jaf/providers/__init__.py +6 -3
  71. jaf/providers/mcp.py +97 -51
  72. jaf/providers/model.py +360 -279
  73. jaf/server/__init__.py +1 -1
  74. jaf/server/main.py +7 -11
  75. jaf/server/server.py +514 -359
  76. jaf/server/types.py +208 -52
  77. jaf/utils/__init__.py +17 -18
  78. jaf/utils/attachments.py +111 -116
  79. jaf/utils/document_processor.py +175 -174
  80. jaf/visualization/__init__.py +1 -1
  81. jaf/visualization/example.py +111 -110
  82. jaf/visualization/functional_core.py +46 -71
  83. jaf/visualization/graphviz.py +154 -189
  84. jaf/visualization/imperative_shell.py +7 -16
  85. jaf/visualization/types.py +8 -4
  86. {jaf_py-2.5.10.dist-info → jaf_py-2.5.11.dist-info}/METADATA +2 -2
  87. jaf_py-2.5.11.dist-info/RECORD +97 -0
  88. jaf_py-2.5.10.dist-info/RECORD +0 -96
  89. {jaf_py-2.5.10.dist-info → jaf_py-2.5.11.dist-info}/WHEEL +0 -0
  90. {jaf_py-2.5.10.dist-info → jaf_py-2.5.11.dist-info}/entry_points.txt +0 -0
  91. {jaf_py-2.5.10.dist-info → jaf_py-2.5.11.dist-info}/licenses/LICENSE +0 -0
  92. {jaf_py-2.5.10.dist-info → jaf_py-2.5.11.dist-info}/top_level.txt +0 -0
jaf/core/errors.py CHANGED
@@ -28,10 +28,10 @@ class JAFErrorHandler:
28
28
  def format_error(error: JAFError) -> str:
29
29
  """
30
30
  Format an error into a human-readable string.
31
-
31
+
32
32
  Args:
33
33
  error: The JAF error to format
34
-
34
+
35
35
  Returns:
36
36
  Formatted error message
37
37
  """
@@ -46,9 +46,13 @@ class JAFErrorHandler:
46
46
  issues = []
47
47
  for e in error.errors:
48
48
  if isinstance(e, dict):
49
- message = e.get('message', 'Unknown error')
50
- if 'path' in e:
51
- path = '.'.join(str(p) for p in e['path']) if isinstance(e['path'], list) else str(e['path'])
49
+ message = e.get("message", "Unknown error")
50
+ if "path" in e:
51
+ path = (
52
+ ".".join(str(p) for p in e["path"])
53
+ if isinstance(e["path"], list)
54
+ else str(e["path"])
55
+ )
52
56
  issues.append(f"{path}: {message}")
53
57
  else:
54
58
  issues.append(message)
@@ -79,101 +83,110 @@ class JAFErrorHandler:
79
83
  def is_retryable(error: JAFError) -> bool:
80
84
  """
81
85
  Determine if an error is retryable.
82
-
86
+
83
87
  Args:
84
88
  error: The JAF error to check
85
-
89
+
86
90
  Returns:
87
91
  True if the error is retryable, False otherwise
88
92
  """
89
93
  if isinstance(error, (ModelBehaviorError, ToolCallError)):
90
94
  return True
91
95
 
92
- elif isinstance(error, (
93
- MaxTurnsExceeded, DecodeError, InputGuardrailTripwire,
94
- OutputGuardrailTripwire, HandoffError, AgentNotFound
95
- )):
96
+ elif isinstance(
97
+ error,
98
+ (
99
+ MaxTurnsExceeded,
100
+ DecodeError,
101
+ InputGuardrailTripwire,
102
+ OutputGuardrailTripwire,
103
+ HandoffError,
104
+ AgentNotFound,
105
+ ),
106
+ ):
96
107
  return False
97
108
 
98
109
  else:
99
110
  return False
100
111
 
101
112
  @staticmethod
102
- def get_severity(error: JAFError) -> Literal['low', 'medium', 'high', 'critical']:
113
+ def get_severity(error: JAFError) -> Literal["low", "medium", "high", "critical"]:
103
114
  """
104
115
  Get the severity level of an error.
105
-
116
+
106
117
  Args:
107
118
  error: The JAF error to classify
108
-
119
+
109
120
  Returns:
110
121
  Severity level: 'low', 'medium', 'high', or 'critical'
111
122
  """
112
123
  if isinstance(error, (ModelBehaviorError, ToolCallError)):
113
- return 'medium'
124
+ return "medium"
114
125
 
115
126
  elif isinstance(error, DecodeError):
116
- return 'high'
127
+ return "high"
117
128
 
118
129
  elif isinstance(error, MaxTurnsExceeded):
119
- return 'low'
130
+ return "low"
120
131
 
121
132
  elif isinstance(error, (InputGuardrailTripwire, OutputGuardrailTripwire)):
122
- return 'high'
133
+ return "high"
123
134
 
124
135
  elif isinstance(error, (HandoffError, AgentNotFound)):
125
- return 'critical'
136
+ return "critical"
126
137
 
127
138
  else:
128
- return 'medium'
139
+ return "medium"
140
+
129
141
 
130
142
  def create_jaf_error(tag: str, details: Any) -> JAFError:
131
143
  """
132
144
  Create a JAF error from a tag and details.
133
-
145
+
134
146
  Args:
135
147
  tag: The error tag/type
136
148
  details: Error details (can be dict or simple value)
137
-
149
+
138
150
  Returns:
139
151
  Appropriate JAF error instance
140
-
152
+
141
153
  Raises:
142
154
  ValueError: If the error tag is unknown
143
155
  """
144
156
  # Normalize details to dict if it's a simple value
145
157
  if not isinstance(details, dict):
146
158
  if isinstance(details, str):
147
- details = {'detail': details}
159
+ details = {"detail": details}
148
160
  else:
149
- details = {'value': details}
161
+ details = {"value": details}
150
162
 
151
- if tag == 'MaxTurnsExceeded':
152
- return MaxTurnsExceeded(turns=details.get('turns', 0))
163
+ if tag == "MaxTurnsExceeded":
164
+ return MaxTurnsExceeded(turns=details.get("turns", 0))
153
165
 
154
- elif tag == 'ModelBehaviorError':
155
- return ModelBehaviorError(detail=details.get('detail', str(details)))
166
+ elif tag == "ModelBehaviorError":
167
+ return ModelBehaviorError(detail=details.get("detail", str(details)))
156
168
 
157
- elif tag == 'DecodeError':
158
- return DecodeError(errors=details.get('errors', []))
169
+ elif tag == "DecodeError":
170
+ return DecodeError(errors=details.get("errors", []))
159
171
 
160
- elif tag == 'InputGuardrailTripwire':
161
- return InputGuardrailTripwire(reason=details.get('reason', str(details)))
172
+ elif tag == "InputGuardrailTripwire":
173
+ return InputGuardrailTripwire(reason=details.get("reason", str(details)))
162
174
 
163
- elif tag == 'OutputGuardrailTripwire':
164
- return OutputGuardrailTripwire(reason=details.get('reason', str(details)))
175
+ elif tag == "OutputGuardrailTripwire":
176
+ return OutputGuardrailTripwire(reason=details.get("reason", str(details)))
165
177
 
166
- elif tag == 'ToolCallError':
178
+ elif tag == "ToolCallError":
167
179
  return ToolCallError(
168
- tool=details.get('tool', ''),
169
- detail=details.get('detail', str(details))
180
+ tool=details.get("tool", ""), detail=details.get("detail", str(details))
170
181
  )
171
182
 
172
- elif tag == 'HandoffError':
173
- return HandoffError(detail=details.get('detail', str(details)))
183
+ elif tag == "HandoffError":
184
+ return HandoffError(detail=details.get("detail", str(details)))
174
185
 
175
- elif tag == 'AgentNotFound':
176
- return AgentNotFound(agent_name=details.get('agentName', details.get('agent_name', str(details))))
186
+ elif tag == "AgentNotFound":
187
+ return AgentNotFound(
188
+ agent_name=details.get("agentName", details.get("agent_name", str(details)))
189
+ )
177
190
 
178
191
  else:
179
192
  raise ValueError(f"Unknown error tag: {tag}")