fred-runtime 3.3.3__tar.gz → 3.3.6__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.
Files changed (154) hide show
  1. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/PKG-INFO +5 -5
  2. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/app/agent_app.py +6 -5
  3. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/capabilities/document_access/capability.py +47 -5
  4. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/cli/pod_client.py +2 -1
  5. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/deep/deep_runtime.py +46 -8
  6. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/integrations/kf_vector_search/toolkit.py +6 -3
  7. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/integrations/v2_runtime/adapters.py +9 -2
  8. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/react/react_runtime.py +36 -1
  9. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/runtime_support/sql_checkpointer.py +17 -2
  10. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime.egg-info/PKG-INFO +5 -5
  11. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime.egg-info/SOURCES.txt +2 -0
  12. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime.egg-info/requires.txt +4 -4
  13. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/pyproject.toml +5 -5
  14. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_agent_app.py +80 -0
  15. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_capability_document_access_1906.py +94 -3
  16. fred_runtime-3.3.6/tests/test_deep_agent_middleware.py +182 -0
  17. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_kf_vector_search_toolkit.py +41 -0
  18. fred_runtime-3.3.6/tests/test_knowledge_search_tool_invoker_sources.py +104 -0
  19. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_react_thinking.py +38 -0
  20. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_sql_checkpointer_owner.py +18 -0
  21. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/README.md +0 -0
  22. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/__init__.py +0 -0
  23. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/__main__.py +0 -0
  24. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/app/__init__.py +0 -0
  25. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/app/_catalogs.py +0 -0
  26. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/app/config.py +0 -0
  27. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/app/config_loader.py +0 -0
  28. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/app/container.py +0 -0
  29. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/app/context.py +0 -0
  30. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/app/dependencies.py +0 -0
  31. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/app/mcp_config.py +0 -0
  32. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/app/observability_factory.py +0 -0
  33. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/app/openai_compat_router.py +0 -0
  34. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/capabilities/__init__.py +0 -0
  35. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/capabilities/assembly.py +0 -0
  36. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/capabilities/assets.py +0 -0
  37. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/capabilities/demo.py +0 -0
  38. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/capabilities/demo_migrations/env.py +0 -0
  39. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/capabilities/demo_migrations/versions/d1e2m0a0b0c0_create_demo_echo_notes.py +0 -0
  40. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/capabilities/document_access/__init__.py +0 -0
  41. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/capabilities/errors.py +0 -0
  42. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/capabilities/mcp.py +0 -0
  43. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/capabilities/openapi_dump.py +0 -0
  44. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/capabilities/registry.py +0 -0
  45. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/cli/__init__.py +0 -0
  46. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/cli/completion.py +0 -0
  47. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/cli/entrypoint.py +0 -0
  48. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/cli/history_display.py +0 -0
  49. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/cli/kpi_display.py +0 -0
  50. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/cli/repl.py +0 -0
  51. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/cli/repl_helpers.py +0 -0
  52. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/cli/url_helpers.py +0 -0
  53. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/client.py +0 -0
  54. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/common/__init__.py +0 -0
  55. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/common/context_aware_tool.py +0 -0
  56. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/common/kf_base_client.py +0 -0
  57. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/common/kf_fast_text_client.py +0 -0
  58. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/common/kf_http_client.py +0 -0
  59. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/common/kf_markdown_media_client.py +0 -0
  60. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/common/kf_vectorsearch_client.py +0 -0
  61. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/common/kf_workspace_client.py +0 -0
  62. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/common/mcp_interceptors.py +0 -0
  63. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/common/mcp_runtime.py +0 -0
  64. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/common/mcp_toolkit.py +0 -0
  65. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/common/mcp_utils.py +0 -0
  66. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/common/structures.py +0 -0
  67. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/common/token_expiry.py +0 -0
  68. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/common/tool_node_utils.py +0 -0
  69. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/deep/__init__.py +0 -0
  70. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/eval/__init__.py +0 -0
  71. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/eval/collector.py +0 -0
  72. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/graph/__init__.py +0 -0
  73. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/graph/graph_runtime.py +0 -0
  74. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/integrations/__init__.py +0 -0
  75. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/integrations/inprocess_toolkit_registry.py +0 -0
  76. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/integrations/kf_vector_search/__init__.py +0 -0
  77. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/integrations/v2_runtime/__init__.py +0 -0
  78. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/migrations.py +0 -0
  79. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/model_routing/__init__.py +0 -0
  80. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/model_routing/catalog.py +0 -0
  81. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/model_routing/contracts.py +0 -0
  82. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/model_routing/provider.py +0 -0
  83. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/model_routing/resolver.py +0 -0
  84. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/react/__init__.py +0 -0
  85. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/react/middleware/__init__.py +0 -0
  86. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/react/middleware/checkpoint_hygiene.py +0 -0
  87. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/react/middleware/dynamic_prompt.py +0 -0
  88. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/react/middleware/frame.py +0 -0
  89. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/react/middleware/hitl.py +0 -0
  90. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/react/middleware/model_routing.py +0 -0
  91. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/react/middleware/shared.py +0 -0
  92. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/react/middleware/tool_observability.py +0 -0
  93. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/react/middleware/tracing_kpi.py +0 -0
  94. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/react/react_langchain_adapter.py +0 -0
  95. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/react/react_message_codec.py +0 -0
  96. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/react/react_model_adapter.py +0 -0
  97. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/react/react_prompting.py +0 -0
  98. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/react/react_stream_adapter.py +0 -0
  99. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/react/react_tool_binding.py +0 -0
  100. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/react/react_tool_loop.py +0 -0
  101. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/react/react_tool_rendering.py +0 -0
  102. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/react/react_tool_resolution.py +0 -0
  103. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/react/react_tool_utils.py +0 -0
  104. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/react/react_tracing.py +0 -0
  105. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/runtime_context.py +0 -0
  106. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/runtime_support/__init__.py +0 -0
  107. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/runtime_support/checkpoints.py +0 -0
  108. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/runtime_support/model_metadata.py +0 -0
  109. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/runtime_support/request_context_helpers.py +0 -0
  110. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/runtime_support/user_token_refresher.py +0 -0
  111. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/support/__init__.py +0 -0
  112. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/support/filesystem_context.py +0 -0
  113. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/support/thinking.py +0 -0
  114. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/support/tool_loop.py +0 -0
  115. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime.egg-info/dependency_links.txt +0 -0
  116. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime.egg-info/entry_points.txt +0 -0
  117. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime.egg-info/top_level.txt +0 -0
  118. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/setup.cfg +0 -0
  119. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_capability_agent_1973.py +0 -0
  120. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_capability_chat_controls_1976.py +0 -0
  121. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_capability_chat_parts_1977.py +0 -0
  122. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_capability_endpoints_1974.py +0 -0
  123. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_capability_registry_1973.py +0 -0
  124. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_capability_routes_tables_1979.py +0 -0
  125. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_capability_selection_1974.py +0 -0
  126. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_client.py +0 -0
  127. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_config_loader.py +0 -0
  128. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_context.py +0 -0
  129. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_context_aware_tool.py +0 -0
  130. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_conversational_memory.py +0 -0
  131. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_eval_collector.py +0 -0
  132. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_eval_trace.py +0 -0
  133. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_fred_workspace_fs.py +0 -0
  134. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_graph_runtime_invoke_agent.py +0 -0
  135. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_graph_runtime_observability.py +0 -0
  136. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_history.py +0 -0
  137. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_kf_workspace_client.py +0 -0
  138. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_kpi_display.py +0 -0
  139. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_mcp_config.py +0 -0
  140. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_model_routing.py +0 -0
  141. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_openai_compat_router.py +0 -0
  142. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_pod_client.py +0 -0
  143. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_react_loop_regressions_1972.py +0 -0
  144. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_react_middleware_frame.py +0 -0
  145. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_react_prompting.py +0 -0
  146. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_repl_helpers.py +0 -0
  147. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_runtime_context_prompt_injection.py +0 -0
  148. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_smoke.py +0 -0
  149. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_spike_capability_state_1971.py +0 -0
  150. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_token_expiry.py +0 -0
  151. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_tool_observability_middleware.py +0 -0
  152. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_tracing_kpi_content_confinement.py +0 -0
  153. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_url_helpers.py +0 -0
  154. {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_user_token_refresher.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fred-runtime
3
- Version: 3.3.3
3
+ Version: 3.3.6
4
4
  Summary: Runtime adapters and infrastructure wiring for Fred v2 agents.
5
5
  Author-email: Thales <noreply@thalesgroup.com>
6
6
  License: Apache-2.0
@@ -13,14 +13,14 @@ Classifier: Operating System :: OS Independent
13
13
  Requires-Python: <3.13,>=3.12
14
14
  Description-Content-Type: text/markdown
15
15
  Requires-Dist: fred-core>=3.4.1
16
- Requires-Dist: fred-sdk>=3.3.1
16
+ Requires-Dist: fred-sdk>=3.3.3
17
17
  Requires-Dist: alembic>=1.18.4
18
- Requires-Dist: deepagents>=0.4.11
18
+ Requires-Dist: deepagents>=0.6.12
19
19
  Requires-Dist: httpx>=0.28.1
20
20
  Requires-Dist: langchain-mcp-adapters>=0.2.1
21
- Requires-Dist: langchain>=0.3.0
21
+ Requires-Dist: langchain>=1.3.14
22
22
  Requires-Dist: langchain-core>=0.3.0
23
- Requires-Dist: langgraph>=1.1.3
23
+ Requires-Dist: langgraph>=1.2.9
24
24
  Requires-Dist: langfuse>=3.0.0
25
25
  Requires-Dist: requests<3,>=2.32
26
26
  Requires-Dist: PyYAML>=6.0
@@ -3419,13 +3419,12 @@ def _build_agent_router(
3419
3419
 
3420
3420
  @router.delete(
3421
3421
  "/checkpoints/{session_id}",
3422
- status_code=status.HTTP_204_NO_CONTENT,
3423
- response_model=None,
3422
+ status_code=status.HTTP_200_OK,
3424
3423
  )
3425
3424
  async def delete_checkpoint_thread(
3426
3425
  session_id: str,
3427
3426
  caller: KeycloakUser | None = Depends(_authenticated_user),
3428
- ) -> None:
3427
+ ) -> dict[str, int]:
3429
3428
  """
3430
3429
  Purge all checkpoint data for one session.
3431
3430
 
@@ -3438,7 +3437,8 @@ def _build_agent_router(
3438
3437
  History store rows are NOT deleted — use DELETE /sessions/{session_id}
3439
3438
  to remove those separately.
3440
3439
 
3441
- Returns 204 on success, 403 when not owned, 503 when no checkpointer.
3440
+ Returns {"deleted": n} (n = checkpoint rows removed) on success,
3441
+ 403 when not owned, 503 when no checkpointer.
3442
3442
  """
3443
3443
  caller_uid = caller.uid if caller is not None else None
3444
3444
  history_store = _get_history_store_for_owned_access(caller)
@@ -3453,7 +3453,8 @@ def _build_agent_router(
3453
3453
  detail="Access denied.",
3454
3454
  )
3455
3455
  cp = _get_checkpointer()
3456
- await cp.adelete_thread(session_id)
3456
+ deleted = await cp.adelete_thread(session_id)
3457
+ return {"deleted": deleted}
3457
3458
 
3458
3459
  @router.post(
3459
3460
  "/execute",
@@ -62,6 +62,10 @@ from __future__ import annotations
62
62
  import json
63
63
  from collections.abc import Sequence
64
64
 
65
+ from fred_core.store.vector_search import (
66
+ DEFAULT_MIN_SOURCE_SCORE_RATIO,
67
+ select_citable_sources,
68
+ )
65
69
  from fred_sdk.contracts.capability import (
66
70
  AgentCapability,
67
71
  CapabilityContext,
@@ -78,7 +82,7 @@ from fred_sdk.contracts.models import FieldSpec
78
82
  from fred_sdk.contracts.runtime import DocumentSearchResult
79
83
  from langchain.agents.middleware import AgentMiddleware
80
84
  from langchain_core.tools import BaseTool, tool
81
- from pydantic import BaseModel
85
+ from pydantic import BaseModel, Field
82
86
 
83
87
  # The tool-result `tool_ref` this capability stamps on its artifact — distinct
84
88
  # from the builtin `knowledge.search` ref so the two paths stay traceable apart.
@@ -131,6 +135,9 @@ class DocumentAccessConfig(BaseModel):
131
135
  list means "no capability-side narrowing at this level" (the session binding
132
136
  still bounds it). `default_top_k` and `search_policy` set retrieval
133
137
  defaults; `show_document_scope_control` toggles the computed chat control.
138
+ `min_source_score_ratio` bounds what's citable as a "source" in the chat
139
+ UI (RAG-DATASET-DISCOVERY-RFC.md §7) — it never narrows what the model
140
+ itself sees, only what a human is shown as evidence.
134
141
  """
135
142
 
136
143
  library_tag_ids: list[str] = []
@@ -138,6 +145,16 @@ class DocumentAccessConfig(BaseModel):
138
145
  default_top_k: int = 8
139
146
  search_policy: str | None = None
140
147
  show_document_scope_control: bool = True
148
+ min_source_score_ratio: float = Field(
149
+ default=DEFAULT_MIN_SOURCE_SCORE_RATIO,
150
+ ge=0.0,
151
+ le=1.0,
152
+ description=(
153
+ "A hit must score at least this fraction of the best hit in the "
154
+ "same search call to be citable as a source. Does not affect what "
155
+ "the model itself can read — only the human-facing Sources panel."
156
+ ),
157
+ )
141
158
 
142
159
 
143
160
  class DocumentAccessTurnOptions(BaseModel):
@@ -189,6 +206,7 @@ class _DocumentAccessMiddleware(AgentMiddleware):
189
206
  )
190
207
  default_top_k = config.default_top_k if config.default_top_k > 0 else 8
191
208
  search_policy = config.search_policy
209
+ min_source_score_ratio = config.min_source_score_ratio
192
210
 
193
211
  @tool(
194
212
  "search_documents_using_vectorization",
@@ -206,6 +224,10 @@ class _DocumentAccessMiddleware(AgentMiddleware):
206
224
  conversational exchanges (greetings, thanks, clarifying what was just
207
225
  said).
208
226
 
227
+ Covers prose/text documents. If a hit describes a structured/tabular
228
+ dataset (a "dataset pointer"), do not answer from it directly — pivot
229
+ to the tabular/SQL tool it names instead.
230
+
209
231
  Returns ranked hits with title and content. Only use information
210
232
  actually present in the returned hits; never invent facts beyond
211
233
  them.
@@ -241,13 +263,19 @@ class _DocumentAccessMiddleware(AgentMiddleware):
241
263
  for hit in hits
242
264
  ],
243
265
  }
244
- # `blocks` feed the LLM the hit JSON; `sources` carry the typed hits
245
- # the chat Sources panel renders (the runtime merges artifact
246
- # sources onto the tool_result/final events).
266
+ # `blocks` feed the LLM the full hit set (the model needs to see a
267
+ # dataset pointer to know to pivot to the tabular tool, and every
268
+ # hit to reason with) — `sources` (the chat Sources panel) is
269
+ # narrowed separately: never a pointer chunk (no real content to
270
+ # cite), and never a hit that's noise relative to the best match
271
+ # in this call (found live citing near-zero-relevance paragraphs
272
+ # from an unrelated document, RAG-DATASET-DISCOVERY-RFC.md §7).
247
273
  artifact = ToolInvocationResult(
248
274
  tool_ref=DOCUMENT_ACCESS_TOOL_REF,
249
275
  blocks=(ToolContentBlock(kind=ToolContentKind.JSON, data=content),),
250
- sources=tuple(hits),
276
+ sources=select_citable_sources(
277
+ hits, min_score_ratio=min_source_score_ratio
278
+ ),
251
279
  )
252
280
  return json.dumps(content), artifact
253
281
 
@@ -316,6 +344,20 @@ class DocumentAccessCapability(
316
344
  ),
317
345
  default=True,
318
346
  ),
347
+ FieldSpec(
348
+ key="min_source_score_ratio",
349
+ type="number",
350
+ title="Minimum source relevance ratio",
351
+ description=(
352
+ "A hit must score at least this fraction of the best hit "
353
+ "in the same search to be shown as a cited source. Only "
354
+ "affects the human-facing Sources panel, never what the "
355
+ "model itself can read."
356
+ ),
357
+ default=DEFAULT_MIN_SOURCE_SCORE_RATIO,
358
+ min=0.0,
359
+ max=1.0,
360
+ ),
319
361
  ],
320
362
  # No new chat part / side panel / router / owned table — the pilot's
321
363
  # smallest real surface (RFC §10). team_scope=default_on: baseline
@@ -265,10 +265,11 @@ class AgentPodClient:
265
265
  response.raise_for_status()
266
266
  return int(response.json().get("deleted", 0))
267
267
 
268
- def delete_checkpoint(self, session_id: str) -> None:
268
+ def delete_checkpoint(self, session_id: str) -> int:
269
269
  url = f"{self.base_url}/agents/checkpoints/{session_id}"
270
270
  response = self.http_client.delete(url, headers=self._auth_headers())
271
271
  response.raise_for_status()
272
+ return int(response.json().get("deleted", 0))
272
273
 
273
274
  def get_checkpoint_stats(self) -> dict[str, Any]:
274
275
  url = f"{self.base_url}/agents/checkpoints/_stats"
@@ -29,14 +29,25 @@ from __future__ import annotations
29
29
  from collections.abc import Sequence
30
30
  from typing import cast
31
31
 
32
+ from fred_core.kpi import BaseKPIWriter
32
33
  from fred_sdk.contracts.context import BoundRuntimeContext
33
- from fred_sdk.contracts.runtime import Executor
34
+ from fred_sdk.contracts.runtime import Executor, TracerPort
34
35
  from langchain.agents.middleware import AgentMiddleware
35
36
  from langchain.agents.middleware.tool_call_limit import ToolCallLimitMiddleware
36
37
  from langchain_core.language_models.chat_models import BaseChatModel
37
38
  from langchain_core.tools import BaseTool
38
39
  from langgraph.types import Checkpointer
39
40
 
41
+ from fred_runtime.react.middleware.tool_observability import (
42
+ ToolObservabilityMiddleware,
43
+ )
44
+ from fred_runtime.react.middleware.tracing_kpi import TracingKpiMiddleware
45
+ from fred_runtime.react.react_model_adapter import (
46
+ REACT_MODEL_OPERATION_ROUTING,
47
+ )
48
+ from fred_runtime.react.react_model_adapter import (
49
+ infer_react_model_operation_from_messages as _infer_react_model_operation_from_messages,
50
+ )
40
51
  from fred_runtime.react.react_prompting import (
41
52
  compose_system_prompt as _compose_system_prompt,
42
53
  )
@@ -53,6 +64,7 @@ from fred_runtime.react.react_runtime import (
53
64
  )
54
65
  from fred_runtime.react.react_tool_binding import ReActToolBinder
55
66
  from fred_runtime.react.react_tool_resolution import ReActRuntimeToolResolver
67
+ from fred_runtime.runtime_context import get_runtime_context
56
68
 
57
69
  _FILESYSTEM_TOOL_NAMES: tuple[str, ...] = (
58
70
  "ls",
@@ -135,7 +147,10 @@ class DeepAgentRuntime(ReActRuntime):
135
147
  system_prompt=system_prompt,
136
148
  checkpointer=cast(Checkpointer, self.services.checkpointer),
137
149
  middleware=_build_deepagent_runtime_middleware(
138
- filesystem_tools_enabled=filesystem_tools_enabled
150
+ filesystem_tools_enabled=filesystem_tools_enabled,
151
+ tracer=self.services.tracer,
152
+ kpi=get_runtime_context().get_kpi_writer(),
153
+ binding=binding,
139
154
  ),
140
155
  )
141
156
  return _TransportBackedReActExecutor(
@@ -229,12 +244,26 @@ def _filesystem_prompt_suffix(*, filesystem_tools_enabled: bool) -> str:
229
244
 
230
245
 
231
246
  def _build_deepagent_runtime_middleware(
232
- *, filesystem_tools_enabled: bool
247
+ *,
248
+ filesystem_tools_enabled: bool,
249
+ tracer: TracerPort | None,
250
+ kpi: BaseKPIWriter | None,
251
+ binding: BoundRuntimeContext,
233
252
  ) -> list[AgentMiddleware]:
234
253
  """
235
- Build Deep runtime middleware for filesystem-tool policy.
254
+ Build Deep runtime middleware: platform observability first, then the
255
+ filesystem-tool policy guard.
236
256
 
237
257
  Why this exists:
258
+ - Deep used to bypass `build_react_platform_middleware_frame()` entirely
259
+ (it overrides `build_executor`, so it never went through
260
+ `_create_compiled_react_agent`), which meant a Deep turn emitted no
261
+ `[LLM][CALL]`/`[LLM][RESPONSE]` logs, no `llm.call_latency_ms` KPI, and
262
+ no `agent.tool.invocation.*` audit events — the same
263
+ `TracingKpiMiddleware`/`ToolObservabilityMiddleware` pair ReAct always
264
+ gets. `create_deep_agent` accepts a plain `middleware=` list, so the
265
+ fix is to hand it the same two middleware instances, same order, no
266
+ new machinery.
238
267
  - when the standard filesystem MCP tools are absent, Deep should block
239
268
  accidental filesystem calls explicitly
240
269
  - when those tools are present, Deep should not add special blocking and
@@ -243,15 +272,24 @@ def _build_deepagent_runtime_middleware(
243
272
  How to use it:
244
273
  - call once while creating the compiled deep agent
245
274
  - pass whether standard filesystem tools are available in the resolved tool
246
- list
275
+ list, plus the same tracer/kpi/binding used to build the tool bindings
247
276
 
248
277
  Example:
249
- - `middleware = _build_deepagent_runtime_middleware(filesystem_tools_enabled=True)`
278
+ - `middleware = _build_deepagent_runtime_middleware(filesystem_tools_enabled=True, tracer=tracer, kpi=kpi, binding=binding)`
250
279
  """
280
+ middleware: list[AgentMiddleware] = [
281
+ TracingKpiMiddleware(
282
+ tracer=tracer,
283
+ kpi=kpi,
284
+ binding=binding,
285
+ infer_operation_from_messages=_infer_react_model_operation_from_messages,
286
+ default_operation=REACT_MODEL_OPERATION_ROUTING,
287
+ ),
288
+ ToolObservabilityMiddleware(kpi=kpi, binding=binding),
289
+ ]
251
290
  if filesystem_tools_enabled:
252
- return []
291
+ return middleware
253
292
 
254
- middleware: list[AgentMiddleware] = []
255
293
  for tool_name in _FILESYSTEM_TOOL_NAMES:
256
294
  middleware.append(
257
295
  cast(
@@ -49,7 +49,7 @@ from typing import Sequence
49
49
 
50
50
  from fred_core.common import OwnerFilter
51
51
  from fred_core.common.team_id import is_personal_team_id
52
- from fred_core.store.vector_search import VectorSearchHit
52
+ from fred_core.store.vector_search import VectorSearchHit, select_citable_sources
53
53
  from fred_sdk.contracts.context import (
54
54
  ToolContentBlock,
55
55
  ToolContentKind,
@@ -168,7 +168,10 @@ class KfVectorSearchToolkit:
168
168
  # Return a ToolInvocationResult directly: the runtime-provider resolver
169
169
  # invokes this tool with a plain args dict, so a content_and_artifact
170
170
  # tuple would lose the artifact (and its sources). `blocks` feed the LLM
171
- # the hit JSON; `sources` carry the typed hits the Sources panel renders.
171
+ # the full hit set; `sources` (the Sources panel) is narrowed separately
172
+ # never a dataset pointer chunk, never a hit that's noise relative to the
173
+ # best match in this call (RAG-DATASET-DISCOVERY-RFC.md §7). Mirrors
174
+ # `_invoke_knowledge_search`'s use of the same shared default ratio.
172
175
  return ToolInvocationResult(
173
176
  tool_ref=KF_VECTOR_SEARCH_PROVIDER,
174
177
  blocks=(
@@ -180,7 +183,7 @@ class KfVectorSearchToolkit:
180
183
  },
181
184
  ),
182
185
  ),
183
- sources=tuple(hits),
186
+ sources=select_citable_sources(hits),
184
187
  )
185
188
 
186
189
  return [search_documents_using_vectorization]
@@ -48,7 +48,7 @@ from fred_core.kpi.base_kpi_writer import BaseKPIWriter
48
48
  from fred_core.kpi.kpi_writer_structures import KPIActor
49
49
  from fred_core.portable import LoggingTracer, MetricsProvider, Tracer, get_tracer
50
50
  from fred_core.security.oidc import get_keycloak_client_id, get_keycloak_url
51
- from fred_core.store.vector_search import VectorSearchHit
51
+ from fred_core.store.vector_search import VectorSearchHit, select_citable_sources
52
52
  from fred_sdk.contracts.context import (
53
53
  BoundRuntimeContext,
54
54
  FsEntry,
@@ -514,6 +514,13 @@ class FredKnowledgeSearchToolInvoker(ToolInvokerPort):
514
514
  k: v for k, v in hit.model_dump(mode="json").items() if k in _LLM_FIELDS
515
515
  }
516
516
 
517
+ # `sources` is narrowed separately from the model-visible content: never
518
+ # a dataset pointer chunk (no real content to cite), and never a hit
519
+ # that's noise relative to the best match in this call
520
+ # (RAG-DATASET-DISCOVERY-RFC.md §7). This builtin tool predates
521
+ # capability config fields, so unlike document_access's
522
+ # `min_source_score_ratio`, the ratio here is the shared default, not
523
+ # yet independently tunable per agent instance.
517
524
  return ToolInvocationResult(
518
525
  tool_ref=request.tool_ref,
519
526
  blocks=(
@@ -525,7 +532,7 @@ class FredKnowledgeSearchToolInvoker(ToolInvokerPort):
525
532
  },
526
533
  ),
527
534
  ),
528
- sources=tuple(hits),
535
+ sources=select_citable_sources(hits),
529
536
  )
530
537
 
531
538
  async def _invoke_traces_summarize_conversation(
@@ -33,6 +33,7 @@ open.
33
33
  from __future__ import annotations
34
34
 
35
35
  import logging
36
+ import time
36
37
  import uuid
37
38
  from collections.abc import AsyncIterator, Sequence
38
39
  from contextlib import nullcontext
@@ -219,6 +220,11 @@ def _tool_thought_title(tool_name: str) -> str:
219
220
  return f"Calling {readable}"
220
221
 
221
222
 
223
+ def _elapsed_ms_since(started_at: float) -> int:
224
+ """Return the whole-millisecond duration elapsed since a monotonic timestamp."""
225
+ return int((time.monotonic() - started_at) * 1000)
226
+
227
+
222
228
  class _TransportBackedReActExecutor(Executor[ReActInput, ReActOutput]):
223
229
  """
224
230
  Executes one ReAct run against the compiled LangChain/LangGraph agent.
@@ -341,11 +347,15 @@ class _TransportBackedReActExecutor(Executor[ReActInput, ReActOutput]):
341
347
  # Maps tool call_id → thought_id so THOUGHT_END can close the block
342
348
  # opened by THOUGHT_START before the corresponding TOOL_CALL event.
343
349
  active_thought_ids: dict[str, str] = {}
350
+ # Maps tool call_id → monotonic start time so THOUGHT_END can report a
351
+ # real `duration_ms` instead of leaving the field permanently unset.
352
+ active_thought_started_at: dict[str, float] = {}
344
353
  # Open model-native reasoning block (RUNTIME-05 Layer 2b). When a provider
345
354
  # streams reasoning chunks (Mistral ThinkChunk, Claude thinking), they are
346
355
  # promoted to a single THOUGHT block with source="model_native" that must be
347
356
  # closed before the first answer delta and before the run ends.
348
357
  model_native_thought_id: str | None = None
358
+ model_native_thought_started_at: float | None = None
349
359
  phase_timer_ctx.__enter__()
350
360
  try:
351
361
  async for raw_event in self._compiled_agent.astream(
@@ -372,6 +382,7 @@ class _TransportBackedReActExecutor(Executor[ReActInput, ReActOutput]):
372
382
  for fragment in decoded.thought_fragments:
373
383
  if model_native_thought_id is None:
374
384
  model_native_thought_id = uuid.uuid4().hex
385
+ model_native_thought_started_at = time.monotonic()
375
386
  yield ThoughtStartEvent(
376
387
  sequence=sequence,
377
388
  thought_id=model_native_thought_id,
@@ -393,9 +404,15 @@ class _TransportBackedReActExecutor(Executor[ReActInput, ReActOutput]):
393
404
  yield ThoughtEndEvent(
394
405
  sequence=sequence,
395
406
  thought_id=model_native_thought_id,
407
+ duration_ms=_elapsed_ms_since(
408
+ model_native_thought_started_at
409
+ )
410
+ if model_native_thought_started_at is not None
411
+ else None,
396
412
  )
397
413
  sequence += 1
398
414
  model_native_thought_id = None
415
+ model_native_thought_started_at = None
399
416
  if not suppress_assistant_deltas:
400
417
  yield AssistantDeltaRuntimeEvent(
401
418
  sequence=sequence,
@@ -448,11 +465,17 @@ class _TransportBackedReActExecutor(Executor[ReActInput, ReActOutput]):
448
465
  )
449
466
  sequence += 1
450
467
  thought_id = active_thought_ids.pop(message.tool_call_id, None)
468
+ thought_started_at = active_thought_started_at.pop(
469
+ message.tool_call_id, None
470
+ )
451
471
  if thought_id:
452
472
  yield ThoughtEndEvent(
453
473
  sequence=sequence,
454
474
  thought_id=thought_id,
455
475
  conclusion="Error" if is_error else "Done",
476
+ duration_ms=_elapsed_ms_since(thought_started_at)
477
+ if thought_started_at is not None
478
+ else None,
456
479
  )
457
480
  sequence += 1
458
481
  continue
@@ -463,6 +486,7 @@ class _TransportBackedReActExecutor(Executor[ReActInput, ReActOutput]):
463
486
  call_id = str(tool_call.get("id") or "")
464
487
  thought_id = uuid.uuid4().hex
465
488
  active_thought_ids[call_id] = thought_id
489
+ active_thought_started_at[call_id] = time.monotonic()
466
490
  yield ThoughtStartEvent(
467
491
  sequence=sequence,
468
492
  thought_id=thought_id,
@@ -502,9 +526,13 @@ class _TransportBackedReActExecutor(Executor[ReActInput, ReActOutput]):
502
526
  yield ThoughtEndEvent(
503
527
  sequence=sequence,
504
528
  thought_id=model_native_thought_id,
529
+ duration_ms=_elapsed_ms_since(model_native_thought_started_at)
530
+ if model_native_thought_started_at is not None
531
+ else None,
505
532
  )
506
533
  sequence += 1
507
534
  model_native_thought_id = None
535
+ model_native_thought_started_at = None
508
536
 
509
537
  if last_tool_error is not None or last_assistant_message is not None:
510
538
  final_content = (
@@ -532,14 +560,18 @@ class _TransportBackedReActExecutor(Executor[ReActInput, ReActOutput]):
532
560
  is_error=True,
533
561
  )
534
562
  sequence += 1
563
+ thought_started_at = active_thought_started_at.get(call_id)
535
564
  yield ThoughtEndEvent(
536
565
  sequence=sequence,
537
566
  thought_id=thought_id,
538
567
  conclusion="Error",
539
- duration_ms=None,
568
+ duration_ms=_elapsed_ms_since(thought_started_at)
569
+ if thought_started_at is not None
570
+ else None,
540
571
  )
541
572
  sequence += 1
542
573
  active_thought_ids.clear()
574
+ active_thought_started_at.clear()
543
575
  # Close an open model-native reasoning block so its accordion does not
544
576
  # spin forever after a mid-stream failure.
545
577
  if model_native_thought_id is not None:
@@ -547,6 +579,9 @@ class _TransportBackedReActExecutor(Executor[ReActInput, ReActOutput]):
547
579
  sequence=sequence,
548
580
  thought_id=model_native_thought_id,
549
581
  conclusion="Error",
582
+ duration_ms=_elapsed_ms_since(model_native_thought_started_at)
583
+ if model_native_thought_started_at is not None
584
+ else None,
550
585
  )
551
586
  sequence += 1
552
587
  raise
@@ -589,7 +589,21 @@ class FredSqlCheckpointer(BaseCheckpointSaver[str]):
589
589
  def delete_thread(self, thread_id: str) -> None: # type: ignore[override]
590
590
  raise _sync_checkpointer_error("delete_thread")
591
591
 
592
- async def adelete_thread(self, thread_id: str) -> None:
592
+ async def adelete_thread(self, thread_id: str) -> int: # type: ignore[override]
593
+ """
594
+ Delete all checkpoint rows for one thread and return the checkpoint count.
595
+
596
+ Why this exists:
597
+ - Callers erasing a conversation (CTRLP-12) need an honest deleted-row
598
+ count for their receipt, matching the sibling history-store delete
599
+ which already returns one. Before this, callers had no way to know
600
+ how much was actually purged.
601
+ - The returned count is the number of rows removed from
602
+ `checkpoints_table` (one row per turn) — the same unit the
603
+ `/agents/checkpoints/{session_id}` listing endpoint reports elsewhere.
604
+ `writes`/`blobs`/`thread_owner` rows are still purged but are
605
+ implementation detail, not a separately meaningful count.
606
+ """
593
607
  async with self.phase("v2_checkpoint_delete_thread"):
594
608
  await self._ensure_tables()
595
609
  async with self.store.begin() as conn:
@@ -598,7 +612,7 @@ class FredSqlCheckpointer(BaseCheckpointSaver[str]):
598
612
  self.writes_table.c.thread_id == thread_id
599
613
  )
600
614
  )
601
- await conn.execute(
615
+ result = await conn.execute(
602
616
  delete(self.checkpoints_table).where(
603
617
  self.checkpoints_table.c.thread_id == thread_id
604
618
  )
@@ -616,6 +630,7 @@ class FredSqlCheckpointer(BaseCheckpointSaver[str]):
616
630
  self.thread_owner_table.c.thread_id == thread_id
617
631
  )
618
632
  )
633
+ return result.rowcount or 0
619
634
 
620
635
  # ------------------------- owner / age index (CTRLP-12 A4) -------------------------
621
636
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fred-runtime
3
- Version: 3.3.3
3
+ Version: 3.3.6
4
4
  Summary: Runtime adapters and infrastructure wiring for Fred v2 agents.
5
5
  Author-email: Thales <noreply@thalesgroup.com>
6
6
  License: Apache-2.0
@@ -13,14 +13,14 @@ Classifier: Operating System :: OS Independent
13
13
  Requires-Python: <3.13,>=3.12
14
14
  Description-Content-Type: text/markdown
15
15
  Requires-Dist: fred-core>=3.4.1
16
- Requires-Dist: fred-sdk>=3.3.1
16
+ Requires-Dist: fred-sdk>=3.3.3
17
17
  Requires-Dist: alembic>=1.18.4
18
- Requires-Dist: deepagents>=0.4.11
18
+ Requires-Dist: deepagents>=0.6.12
19
19
  Requires-Dist: httpx>=0.28.1
20
20
  Requires-Dist: langchain-mcp-adapters>=0.2.1
21
- Requires-Dist: langchain>=0.3.0
21
+ Requires-Dist: langchain>=1.3.14
22
22
  Requires-Dist: langchain-core>=0.3.0
23
- Requires-Dist: langgraph>=1.1.3
23
+ Requires-Dist: langgraph>=1.2.9
24
24
  Requires-Dist: langfuse>=3.0.0
25
25
  Requires-Dist: requests<3,>=2.32
26
26
  Requires-Dist: PyYAML>=6.0
@@ -121,6 +121,7 @@ tests/test_config_loader.py
121
121
  tests/test_context.py
122
122
  tests/test_context_aware_tool.py
123
123
  tests/test_conversational_memory.py
124
+ tests/test_deep_agent_middleware.py
124
125
  tests/test_eval_collector.py
125
126
  tests/test_eval_trace.py
126
127
  tests/test_fred_workspace_fs.py
@@ -129,6 +130,7 @@ tests/test_graph_runtime_observability.py
129
130
  tests/test_history.py
130
131
  tests/test_kf_vector_search_toolkit.py
131
132
  tests/test_kf_workspace_client.py
133
+ tests/test_knowledge_search_tool_invoker_sources.py
132
134
  tests/test_kpi_display.py
133
135
  tests/test_mcp_config.py
134
136
  tests/test_model_routing.py
@@ -1,12 +1,12 @@
1
1
  fred-core>=3.4.1
2
- fred-sdk>=3.3.1
2
+ fred-sdk>=3.3.3
3
3
  alembic>=1.18.4
4
- deepagents>=0.4.11
4
+ deepagents>=0.6.12
5
5
  httpx>=0.28.1
6
6
  langchain-mcp-adapters>=0.2.1
7
- langchain>=0.3.0
7
+ langchain>=1.3.14
8
8
  langchain-core>=0.3.0
9
- langgraph>=1.1.3
9
+ langgraph>=1.2.9
10
10
  langfuse>=3.0.0
11
11
  requests<3,>=2.32
12
12
  PyYAML>=6.0
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "fred-runtime"
3
- version = "3.3.3"
3
+ version = "3.3.6"
4
4
  description = "Runtime adapters and infrastructure wiring for Fred v2 agents."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.12,<3.13"
@@ -8,14 +8,14 @@ license = { text = "Apache-2.0" }
8
8
  authors = [{ name = "Thales", email = "noreply@thalesgroup.com" }]
9
9
  dependencies = [
10
10
  "fred-core>=3.4.1",
11
- "fred-sdk>=3.3.1",
11
+ "fred-sdk>=3.3.3",
12
12
  "alembic>=1.18.4",
13
- "deepagents>=0.4.11",
13
+ "deepagents>=0.6.12",
14
14
  "httpx>=0.28.1",
15
15
  "langchain-mcp-adapters>=0.2.1",
16
- "langchain>=0.3.0",
16
+ "langchain>=1.3.14",
17
17
  "langchain-core>=0.3.0",
18
- "langgraph>=1.1.3",
18
+ "langgraph>=1.2.9",
19
19
  "langfuse>=3.0.0",
20
20
  "requests>=2.32,<3",
21
21
  "PyYAML>=6.0",