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.
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/PKG-INFO +5 -5
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/app/agent_app.py +6 -5
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/capabilities/document_access/capability.py +47 -5
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/cli/pod_client.py +2 -1
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/deep/deep_runtime.py +46 -8
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/integrations/kf_vector_search/toolkit.py +6 -3
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/integrations/v2_runtime/adapters.py +9 -2
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/react/react_runtime.py +36 -1
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/runtime_support/sql_checkpointer.py +17 -2
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime.egg-info/PKG-INFO +5 -5
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime.egg-info/SOURCES.txt +2 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime.egg-info/requires.txt +4 -4
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/pyproject.toml +5 -5
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_agent_app.py +80 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_capability_document_access_1906.py +94 -3
- fred_runtime-3.3.6/tests/test_deep_agent_middleware.py +182 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_kf_vector_search_toolkit.py +41 -0
- fred_runtime-3.3.6/tests/test_knowledge_search_tool_invoker_sources.py +104 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_react_thinking.py +38 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_sql_checkpointer_owner.py +18 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/README.md +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/__init__.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/__main__.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/app/__init__.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/app/_catalogs.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/app/config.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/app/config_loader.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/app/container.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/app/context.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/app/dependencies.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/app/mcp_config.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/app/observability_factory.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/app/openai_compat_router.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/capabilities/__init__.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/capabilities/assembly.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/capabilities/assets.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/capabilities/demo.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/capabilities/demo_migrations/env.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/capabilities/demo_migrations/versions/d1e2m0a0b0c0_create_demo_echo_notes.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/capabilities/document_access/__init__.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/capabilities/errors.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/capabilities/mcp.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/capabilities/openapi_dump.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/capabilities/registry.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/cli/__init__.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/cli/completion.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/cli/entrypoint.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/cli/history_display.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/cli/kpi_display.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/cli/repl.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/cli/repl_helpers.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/cli/url_helpers.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/client.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/common/__init__.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/common/context_aware_tool.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/common/kf_base_client.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/common/kf_fast_text_client.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/common/kf_http_client.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/common/kf_markdown_media_client.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/common/kf_vectorsearch_client.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/common/kf_workspace_client.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/common/mcp_interceptors.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/common/mcp_runtime.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/common/mcp_toolkit.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/common/mcp_utils.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/common/structures.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/common/token_expiry.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/common/tool_node_utils.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/deep/__init__.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/eval/__init__.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/eval/collector.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/graph/__init__.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/graph/graph_runtime.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/integrations/__init__.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/integrations/inprocess_toolkit_registry.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/integrations/kf_vector_search/__init__.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/integrations/v2_runtime/__init__.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/migrations.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/model_routing/__init__.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/model_routing/catalog.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/model_routing/contracts.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/model_routing/provider.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/model_routing/resolver.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/react/__init__.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/react/middleware/__init__.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/react/middleware/checkpoint_hygiene.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/react/middleware/dynamic_prompt.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/react/middleware/frame.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/react/middleware/hitl.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/react/middleware/model_routing.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/react/middleware/shared.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/react/middleware/tool_observability.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/react/middleware/tracing_kpi.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/react/react_langchain_adapter.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/react/react_message_codec.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/react/react_model_adapter.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/react/react_prompting.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/react/react_stream_adapter.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/react/react_tool_binding.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/react/react_tool_loop.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/react/react_tool_rendering.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/react/react_tool_resolution.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/react/react_tool_utils.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/react/react_tracing.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/runtime_context.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/runtime_support/__init__.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/runtime_support/checkpoints.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/runtime_support/model_metadata.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/runtime_support/request_context_helpers.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/runtime_support/user_token_refresher.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/support/__init__.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/support/filesystem_context.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/support/thinking.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/support/tool_loop.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime.egg-info/dependency_links.txt +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime.egg-info/entry_points.txt +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime.egg-info/top_level.txt +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/setup.cfg +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_capability_agent_1973.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_capability_chat_controls_1976.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_capability_chat_parts_1977.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_capability_endpoints_1974.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_capability_registry_1973.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_capability_routes_tables_1979.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_capability_selection_1974.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_client.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_config_loader.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_context.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_context_aware_tool.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_conversational_memory.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_eval_collector.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_eval_trace.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_fred_workspace_fs.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_graph_runtime_invoke_agent.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_graph_runtime_observability.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_history.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_kf_workspace_client.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_kpi_display.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_mcp_config.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_model_routing.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_openai_compat_router.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_pod_client.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_react_loop_regressions_1972.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_react_middleware_frame.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_react_prompting.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_repl_helpers.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_runtime_context_prompt_injection.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_smoke.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_spike_capability_state_1971.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_token_expiry.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_tool_observability_middleware.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_tracing_kpi_content_confinement.py +0 -0
- {fred_runtime-3.3.3 → fred_runtime-3.3.6}/tests/test_url_helpers.py +0 -0
- {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
|
+
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.
|
|
16
|
+
Requires-Dist: fred-sdk>=3.3.3
|
|
17
17
|
Requires-Dist: alembic>=1.18.4
|
|
18
|
-
Requires-Dist: deepagents>=0.
|
|
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>=
|
|
21
|
+
Requires-Dist: langchain>=1.3.14
|
|
22
22
|
Requires-Dist: langchain-core>=0.3.0
|
|
23
|
-
Requires-Dist: langgraph>=1.
|
|
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.
|
|
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
|
-
) ->
|
|
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
|
|
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",
|
{fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/capabilities/document_access/capability.py
RENAMED
|
@@ -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
|
|
245
|
-
#
|
|
246
|
-
# sources
|
|
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=
|
|
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) ->
|
|
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
|
-
*,
|
|
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
|
|
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(
|
{fred_runtime-3.3.3 → fred_runtime-3.3.6}/fred_runtime/integrations/kf_vector_search/toolkit.py
RENAMED
|
@@ -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
|
|
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=
|
|
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=
|
|
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=
|
|
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) ->
|
|
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
|
+
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.
|
|
16
|
+
Requires-Dist: fred-sdk>=3.3.3
|
|
17
17
|
Requires-Dist: alembic>=1.18.4
|
|
18
|
-
Requires-Dist: deepagents>=0.
|
|
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>=
|
|
21
|
+
Requires-Dist: langchain>=1.3.14
|
|
22
22
|
Requires-Dist: langchain-core>=0.3.0
|
|
23
|
-
Requires-Dist: langgraph>=1.
|
|
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.
|
|
2
|
+
fred-sdk>=3.3.3
|
|
3
3
|
alembic>=1.18.4
|
|
4
|
-
deepagents>=0.
|
|
4
|
+
deepagents>=0.6.12
|
|
5
5
|
httpx>=0.28.1
|
|
6
6
|
langchain-mcp-adapters>=0.2.1
|
|
7
|
-
langchain>=
|
|
7
|
+
langchain>=1.3.14
|
|
8
8
|
langchain-core>=0.3.0
|
|
9
|
-
langgraph>=1.
|
|
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
|
+
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.
|
|
11
|
+
"fred-sdk>=3.3.3",
|
|
12
12
|
"alembic>=1.18.4",
|
|
13
|
-
"deepagents>=0.
|
|
13
|
+
"deepagents>=0.6.12",
|
|
14
14
|
"httpx>=0.28.1",
|
|
15
15
|
"langchain-mcp-adapters>=0.2.1",
|
|
16
|
-
"langchain>=
|
|
16
|
+
"langchain>=1.3.14",
|
|
17
17
|
"langchain-core>=0.3.0",
|
|
18
|
-
"langgraph>=1.
|
|
18
|
+
"langgraph>=1.2.9",
|
|
19
19
|
"langfuse>=3.0.0",
|
|
20
20
|
"requests>=2.32,<3",
|
|
21
21
|
"PyYAML>=6.0",
|