fred-runtime 2.0.4__tar.gz → 2.0.8__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-2.0.4 → fred_runtime-2.0.8}/PKG-INFO +51 -36
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/README.md +50 -35
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/app/_catalogs.py +31 -1
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/app/agent_app.py +190 -78
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/app/config.py +9 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/cli/completion.py +1 -1
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/common/context_aware_tool.py +35 -2
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/common/kf_workspace_client.py +18 -6
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/deep/deep_runtime.py +0 -3
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/graph/graph_runtime.py +135 -11
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/integrations/v2_runtime/adapters.py +73 -47
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/react/react_prompting.py +25 -38
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/react/react_runtime.py +53 -2
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime.egg-info/PKG-INFO +51 -36
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/pyproject.toml +1 -1
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/tests/test_agent_app.py +186 -2
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/tests/test_config_loader.py +81 -3
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/tests/test_conversational_memory.py +3 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/tests/test_graph_runtime_observability.py +11 -1
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/tests/test_history.py +131 -2
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/tests/test_mcp_config.py +33 -1
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/tests/test_model_routing.py +13 -6
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/__init__.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/app/__init__.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/app/config_loader.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/app/container.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/app/context.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/app/dependencies.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/app/mcp_config.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/app/observability_factory.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/app/openai_compat_router.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/cli/__init__.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/cli/entrypoint.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/cli/history_display.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/cli/kpi_display.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/cli/pod_client.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/cli/repl.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/cli/repl_helpers.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/cli/url_helpers.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/client.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/common/__init__.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/common/kf_base_client.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/common/kf_fast_text_client.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/common/kf_http_client.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/common/kf_logs_client.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/common/kf_markdown_media_client.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/common/kf_vectorsearch_client.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/common/mcp_interceptors.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/common/mcp_runtime.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/common/mcp_toolkit.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/common/mcp_utils.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/common/structures.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/common/token_expiry.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/common/tool_node_utils.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/deep/__init__.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/eval/__init__.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/eval/collector.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/graph/__init__.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/integrations/__init__.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/integrations/v2_runtime/__init__.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/model_routing/__init__.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/model_routing/catalog.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/model_routing/contracts.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/model_routing/provider.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/model_routing/resolver.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/react/__init__.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/react/react_langchain_adapter.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/react/react_message_codec.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/react/react_model_adapter.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/react/react_stream_adapter.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/react/react_tool_binding.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/react/react_tool_loop.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/react/react_tool_rendering.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/react/react_tool_resolution.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/react/react_tool_utils.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/react/react_tracing.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/runtime_context.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/runtime_support/__init__.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/runtime_support/checkpoints.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/runtime_support/model_metadata.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/runtime_support/request_context_helpers.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/runtime_support/sql_checkpointer.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/runtime_support/user_token_refresher.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/support/__init__.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/support/filesystem_context.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/support/tool_approval.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime/support/tool_loop.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime.egg-info/SOURCES.txt +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime.egg-info/dependency_links.txt +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime.egg-info/entry_points.txt +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime.egg-info/requires.txt +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/fred_runtime.egg-info/top_level.txt +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/setup.cfg +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/tests/test_client.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/tests/test_context.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/tests/test_eval_collector.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/tests/test_eval_trace.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/tests/test_kf_workspace_client.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/tests/test_kpi_display.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/tests/test_openai_compat_router.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/tests/test_pod_client.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/tests/test_repl_helpers.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/tests/test_smoke.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/tests/test_token_expiry.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/tests/test_url_helpers.py +0 -0
- {fred_runtime-2.0.4 → fred_runtime-2.0.8}/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: 2.0.
|
|
3
|
+
Version: 2.0.8
|
|
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
|
|
@@ -58,8 +58,9 @@ fred-runtime Platform adapters + pod factory (this package)
|
|
|
58
58
|
```
|
|
59
59
|
|
|
60
60
|
**Rule of thumb:**
|
|
61
|
-
|
|
62
|
-
- Write
|
|
61
|
+
|
|
62
|
+
- Write agent logic in `fred-sdk`.
|
|
63
|
+
- Write infrastructure adapters (DB, MCP server, Keycloak, object store) in `fred-runtime`.
|
|
63
64
|
- `fred-sdk` must stay importable on a bare laptop with no services running.
|
|
64
65
|
|
|
65
66
|
---
|
|
@@ -79,15 +80,15 @@ app = create_agent_app(registry=REGISTRY, config=config)
|
|
|
79
80
|
|
|
80
81
|
`create_agent_app` returns a FastAPI application that exposes:
|
|
81
82
|
|
|
82
|
-
| Method | Path
|
|
83
|
-
|
|
84
|
-
| `POST` | `{base_url}/agents/execute`
|
|
85
|
-
| `POST` | `{base_url}/agents/execute/stream`
|
|
86
|
-
| `GET` | `{base_url}/agents`
|
|
87
|
-
| `GET` | `{base_url}/agents/sessions`
|
|
88
|
-
| `GET` | `{base_url}/agents/sessions/{id}/messages` | Full conversation history for a session
|
|
89
|
-
| `GET` | `/v1/models`
|
|
90
|
-
| `POST` | `/v1/chat/completions`
|
|
83
|
+
| Method | Path | Description |
|
|
84
|
+
| ------ | ------------------------------------------ | ------------------------------------------------------------------------ |
|
|
85
|
+
| `POST` | `{base_url}/agents/execute` | Single-turn execution — returns final JSON |
|
|
86
|
+
| `POST` | `{base_url}/agents/execute/stream` | Streaming SSE execution — yields `RuntimeEvent` objects |
|
|
87
|
+
| `GET` | `{base_url}/agents` | List registered agent IDs |
|
|
88
|
+
| `GET` | `{base_url}/agents/sessions` | List session IDs for a user |
|
|
89
|
+
| `GET` | `{base_url}/agents/sessions/{id}/messages` | Full conversation history for a session |
|
|
90
|
+
| `GET` | `/v1/models` | OpenAI model list (agent IDs as model names) |
|
|
91
|
+
| `POST` | `/v1/chat/completions` | OpenAI chat completions — works with Open WebUI, openai-python SDK, etc. |
|
|
91
92
|
|
|
92
93
|
The OpenAI-compatible `/v1` surface is **enabled by default**.
|
|
93
94
|
Set `app.openai_compat: false` in `configuration.yaml` to disable it for internal pods.
|
|
@@ -99,11 +100,11 @@ the SQL checkpointer. The session ID is the LangGraph `thread_id`.
|
|
|
99
100
|
|
|
100
101
|
### `fred_runtime.runtime_support` — Infrastructure adapters
|
|
101
102
|
|
|
102
|
-
| Module
|
|
103
|
-
|
|
104
|
-
| `sql_checkpointer`
|
|
105
|
-
| `user_token_refresher`
|
|
106
|
-
| `request_context_helpers` | FastAPI dependency helpers for extracting user/session context
|
|
103
|
+
| Module | What it provides |
|
|
104
|
+
| ------------------------- | -------------------------------------------------------------------------- |
|
|
105
|
+
| `sql_checkpointer` | Durable LangGraph checkpointer backed by SQLite (dev) or PostgreSQL (prod) |
|
|
106
|
+
| `user_token_refresher` | Transparent Keycloak token refresh for long-lived agent sessions |
|
|
107
|
+
| `request_context_helpers` | FastAPI dependency helpers for extracting user/session context |
|
|
107
108
|
|
|
108
109
|
---
|
|
109
110
|
|
|
@@ -119,16 +120,16 @@ Providers: OpenAI, Azure OpenAI, Mistral, Ollama, and any LangChain-compatible b
|
|
|
119
120
|
|
|
120
121
|
HTTP clients that connect agent tools to the Fred platform services:
|
|
121
122
|
|
|
122
|
-
| Client
|
|
123
|
-
|
|
124
|
-
| `kf_http_client`
|
|
125
|
-
| `kf_vectorsearch_client`
|
|
126
|
-
| `kf_markdown_media_client`
|
|
127
|
-
| `kf_workspace_client`
|
|
128
|
-
| `kf_logs_client`
|
|
129
|
-
| `kf_fast_text_client`
|
|
130
|
-
| `mcp_runtime` / `mcp_toolkit` | MCP server lifecycle and tool injection
|
|
131
|
-
| `context_aware_tool`
|
|
123
|
+
| Client | Connects to |
|
|
124
|
+
| ----------------------------- | ----------------------------------------------------------------------- |
|
|
125
|
+
| `kf_http_client` | Knowledge Flow REST API (generic) |
|
|
126
|
+
| `kf_vectorsearch_client` | Vector search / retrieval |
|
|
127
|
+
| `kf_markdown_media_client` | Document content (Markdown + media) |
|
|
128
|
+
| `kf_workspace_client` | Workspace and library management |
|
|
129
|
+
| `kf_logs_client` | Audit log retrieval |
|
|
130
|
+
| `kf_fast_text_client` | FastText classification |
|
|
131
|
+
| `mcp_runtime` / `mcp_toolkit` | MCP server lifecycle and tool injection |
|
|
132
|
+
| `context_aware_tool` | Tool base class that propagates the runtime context (user, team, token) |
|
|
132
133
|
|
|
133
134
|
---
|
|
134
135
|
|
|
@@ -176,9 +177,9 @@ or overridden with `--base-url` / `FRED_AGENT_POD_URL`.
|
|
|
176
177
|
|
|
177
178
|
Every Fred pod uses the same two-file convention:
|
|
178
179
|
|
|
179
|
-
| File
|
|
180
|
-
|
|
181
|
-
| `.env` (path from `ENV_FILE`)
|
|
180
|
+
| File | Purpose |
|
|
181
|
+
| ---------------------------------------------- | ------------------------------------------------------------------ |
|
|
182
|
+
| `.env` (path from `ENV_FILE`) | Secrets: API keys, DB URLs, Keycloak credentials |
|
|
182
183
|
| `configuration.yaml` (path from `CONFIG_FILE`) | App settings: port, base URL, LLM routing, observability, security |
|
|
183
184
|
|
|
184
185
|
Minimal `configuration.yaml` for a local pod:
|
|
@@ -190,6 +191,7 @@ app:
|
|
|
190
191
|
host: "0.0.0.0"
|
|
191
192
|
port: 8010
|
|
192
193
|
log_level: "info"
|
|
194
|
+
limit_concurrency: 200
|
|
193
195
|
metrics_address: "127.0.0.1"
|
|
194
196
|
metrics_port: 9115
|
|
195
197
|
kpi_process_metrics_interval_sec: 10
|
|
@@ -208,6 +210,10 @@ When `observability.metrics: prometheus` is enabled, `create_agent_app(...)`
|
|
|
208
210
|
starts a dedicated Prometheus exporter on `app.metrics_address:app.metrics_port`
|
|
209
211
|
and restores the shared Fred KPI pipeline, including process and SQL pool KPIs.
|
|
210
212
|
|
|
213
|
+
Set `app.limit_concurrency: null` to disable Uvicorn connection limiting, or a
|
|
214
|
+
positive integer to reject excess concurrent HTTP and WebSocket connections
|
|
215
|
+
with `503` before application code runs.
|
|
216
|
+
|
|
211
217
|
---
|
|
212
218
|
|
|
213
219
|
## Installation
|
|
@@ -229,6 +235,7 @@ Requires Python 3.12.
|
|
|
229
235
|
A minimal pod is three files:
|
|
230
236
|
|
|
231
237
|
**`main.py`**
|
|
238
|
+
|
|
232
239
|
```python
|
|
233
240
|
from fred_runtime.app import create_agent_app, load_agent_pod_config
|
|
234
241
|
from myapp.registry import REGISTRY
|
|
@@ -238,19 +245,27 @@ app = create_agent_app(registry=REGISTRY, config=config)
|
|
|
238
245
|
```
|
|
239
246
|
|
|
240
247
|
**`__main__.py`**
|
|
248
|
+
|
|
241
249
|
```python
|
|
242
250
|
import uvicorn
|
|
243
251
|
from fred_runtime.app import load_agent_pod_config
|
|
244
252
|
|
|
245
253
|
def main():
|
|
246
254
|
config = load_agent_pod_config()
|
|
247
|
-
uvicorn.run(
|
|
255
|
+
uvicorn.run(
|
|
256
|
+
"myapp.main:app",
|
|
257
|
+
host=config.app.host,
|
|
258
|
+
port=config.app.port,
|
|
259
|
+
limit_concurrency=config.app.limit_concurrency,
|
|
260
|
+
reload=True,
|
|
261
|
+
)
|
|
248
262
|
|
|
249
263
|
if __name__ == "__main__":
|
|
250
264
|
main()
|
|
251
265
|
```
|
|
252
266
|
|
|
253
267
|
**`registry.py`**
|
|
268
|
+
|
|
254
269
|
```python
|
|
255
270
|
from fred_sdk.contracts.models import ReActAgentDefinition
|
|
256
271
|
|
|
@@ -267,11 +282,11 @@ See [fred-samples](https://github.com/ThalesGroup/fred) for a working reference
|
|
|
267
282
|
|
|
268
283
|
## Related packages
|
|
269
284
|
|
|
270
|
-
| Package
|
|
271
|
-
|
|
272
|
-
| `fred-core`
|
|
273
|
-
| `fred-sdk`
|
|
274
|
-
| `fred-runtime` | [pypi](https://pypi.org/project/fred-runtime/) | This package
|
|
285
|
+
| Package | PyPI | Role |
|
|
286
|
+
| -------------- | ---------------------------------------------- | ----------------------------------------------------------------------------- |
|
|
287
|
+
| `fred-core` | [pypi](https://pypi.org/project/fred-core/) | Pure utilities — logging, model factories, embeddings, portable observability |
|
|
288
|
+
| `fred-sdk` | [pypi](https://pypi.org/project/fred-sdk/) | Agent authoring — ReAct, Graph, tool contracts |
|
|
289
|
+
| `fred-runtime` | [pypi](https://pypi.org/project/fred-runtime/) | This package |
|
|
275
290
|
|
|
276
291
|
---
|
|
277
292
|
|
|
@@ -23,8 +23,9 @@ fred-runtime Platform adapters + pod factory (this package)
|
|
|
23
23
|
```
|
|
24
24
|
|
|
25
25
|
**Rule of thumb:**
|
|
26
|
-
|
|
27
|
-
- Write
|
|
26
|
+
|
|
27
|
+
- Write agent logic in `fred-sdk`.
|
|
28
|
+
- Write infrastructure adapters (DB, MCP server, Keycloak, object store) in `fred-runtime`.
|
|
28
29
|
- `fred-sdk` must stay importable on a bare laptop with no services running.
|
|
29
30
|
|
|
30
31
|
---
|
|
@@ -44,15 +45,15 @@ app = create_agent_app(registry=REGISTRY, config=config)
|
|
|
44
45
|
|
|
45
46
|
`create_agent_app` returns a FastAPI application that exposes:
|
|
46
47
|
|
|
47
|
-
| Method | Path
|
|
48
|
-
|
|
49
|
-
| `POST` | `{base_url}/agents/execute`
|
|
50
|
-
| `POST` | `{base_url}/agents/execute/stream`
|
|
51
|
-
| `GET` | `{base_url}/agents`
|
|
52
|
-
| `GET` | `{base_url}/agents/sessions`
|
|
53
|
-
| `GET` | `{base_url}/agents/sessions/{id}/messages` | Full conversation history for a session
|
|
54
|
-
| `GET` | `/v1/models`
|
|
55
|
-
| `POST` | `/v1/chat/completions`
|
|
48
|
+
| Method | Path | Description |
|
|
49
|
+
| ------ | ------------------------------------------ | ------------------------------------------------------------------------ |
|
|
50
|
+
| `POST` | `{base_url}/agents/execute` | Single-turn execution — returns final JSON |
|
|
51
|
+
| `POST` | `{base_url}/agents/execute/stream` | Streaming SSE execution — yields `RuntimeEvent` objects |
|
|
52
|
+
| `GET` | `{base_url}/agents` | List registered agent IDs |
|
|
53
|
+
| `GET` | `{base_url}/agents/sessions` | List session IDs for a user |
|
|
54
|
+
| `GET` | `{base_url}/agents/sessions/{id}/messages` | Full conversation history for a session |
|
|
55
|
+
| `GET` | `/v1/models` | OpenAI model list (agent IDs as model names) |
|
|
56
|
+
| `POST` | `/v1/chat/completions` | OpenAI chat completions — works with Open WebUI, openai-python SDK, etc. |
|
|
56
57
|
|
|
57
58
|
The OpenAI-compatible `/v1` surface is **enabled by default**.
|
|
58
59
|
Set `app.openai_compat: false` in `configuration.yaml` to disable it for internal pods.
|
|
@@ -64,11 +65,11 @@ the SQL checkpointer. The session ID is the LangGraph `thread_id`.
|
|
|
64
65
|
|
|
65
66
|
### `fred_runtime.runtime_support` — Infrastructure adapters
|
|
66
67
|
|
|
67
|
-
| Module
|
|
68
|
-
|
|
69
|
-
| `sql_checkpointer`
|
|
70
|
-
| `user_token_refresher`
|
|
71
|
-
| `request_context_helpers` | FastAPI dependency helpers for extracting user/session context
|
|
68
|
+
| Module | What it provides |
|
|
69
|
+
| ------------------------- | -------------------------------------------------------------------------- |
|
|
70
|
+
| `sql_checkpointer` | Durable LangGraph checkpointer backed by SQLite (dev) or PostgreSQL (prod) |
|
|
71
|
+
| `user_token_refresher` | Transparent Keycloak token refresh for long-lived agent sessions |
|
|
72
|
+
| `request_context_helpers` | FastAPI dependency helpers for extracting user/session context |
|
|
72
73
|
|
|
73
74
|
---
|
|
74
75
|
|
|
@@ -84,16 +85,16 @@ Providers: OpenAI, Azure OpenAI, Mistral, Ollama, and any LangChain-compatible b
|
|
|
84
85
|
|
|
85
86
|
HTTP clients that connect agent tools to the Fred platform services:
|
|
86
87
|
|
|
87
|
-
| Client
|
|
88
|
-
|
|
89
|
-
| `kf_http_client`
|
|
90
|
-
| `kf_vectorsearch_client`
|
|
91
|
-
| `kf_markdown_media_client`
|
|
92
|
-
| `kf_workspace_client`
|
|
93
|
-
| `kf_logs_client`
|
|
94
|
-
| `kf_fast_text_client`
|
|
95
|
-
| `mcp_runtime` / `mcp_toolkit` | MCP server lifecycle and tool injection
|
|
96
|
-
| `context_aware_tool`
|
|
88
|
+
| Client | Connects to |
|
|
89
|
+
| ----------------------------- | ----------------------------------------------------------------------- |
|
|
90
|
+
| `kf_http_client` | Knowledge Flow REST API (generic) |
|
|
91
|
+
| `kf_vectorsearch_client` | Vector search / retrieval |
|
|
92
|
+
| `kf_markdown_media_client` | Document content (Markdown + media) |
|
|
93
|
+
| `kf_workspace_client` | Workspace and library management |
|
|
94
|
+
| `kf_logs_client` | Audit log retrieval |
|
|
95
|
+
| `kf_fast_text_client` | FastText classification |
|
|
96
|
+
| `mcp_runtime` / `mcp_toolkit` | MCP server lifecycle and tool injection |
|
|
97
|
+
| `context_aware_tool` | Tool base class that propagates the runtime context (user, team, token) |
|
|
97
98
|
|
|
98
99
|
---
|
|
99
100
|
|
|
@@ -141,9 +142,9 @@ or overridden with `--base-url` / `FRED_AGENT_POD_URL`.
|
|
|
141
142
|
|
|
142
143
|
Every Fred pod uses the same two-file convention:
|
|
143
144
|
|
|
144
|
-
| File
|
|
145
|
-
|
|
146
|
-
| `.env` (path from `ENV_FILE`)
|
|
145
|
+
| File | Purpose |
|
|
146
|
+
| ---------------------------------------------- | ------------------------------------------------------------------ |
|
|
147
|
+
| `.env` (path from `ENV_FILE`) | Secrets: API keys, DB URLs, Keycloak credentials |
|
|
147
148
|
| `configuration.yaml` (path from `CONFIG_FILE`) | App settings: port, base URL, LLM routing, observability, security |
|
|
148
149
|
|
|
149
150
|
Minimal `configuration.yaml` for a local pod:
|
|
@@ -155,6 +156,7 @@ app:
|
|
|
155
156
|
host: "0.0.0.0"
|
|
156
157
|
port: 8010
|
|
157
158
|
log_level: "info"
|
|
159
|
+
limit_concurrency: 200
|
|
158
160
|
metrics_address: "127.0.0.1"
|
|
159
161
|
metrics_port: 9115
|
|
160
162
|
kpi_process_metrics_interval_sec: 10
|
|
@@ -173,6 +175,10 @@ When `observability.metrics: prometheus` is enabled, `create_agent_app(...)`
|
|
|
173
175
|
starts a dedicated Prometheus exporter on `app.metrics_address:app.metrics_port`
|
|
174
176
|
and restores the shared Fred KPI pipeline, including process and SQL pool KPIs.
|
|
175
177
|
|
|
178
|
+
Set `app.limit_concurrency: null` to disable Uvicorn connection limiting, or a
|
|
179
|
+
positive integer to reject excess concurrent HTTP and WebSocket connections
|
|
180
|
+
with `503` before application code runs.
|
|
181
|
+
|
|
176
182
|
---
|
|
177
183
|
|
|
178
184
|
## Installation
|
|
@@ -194,6 +200,7 @@ Requires Python 3.12.
|
|
|
194
200
|
A minimal pod is three files:
|
|
195
201
|
|
|
196
202
|
**`main.py`**
|
|
203
|
+
|
|
197
204
|
```python
|
|
198
205
|
from fred_runtime.app import create_agent_app, load_agent_pod_config
|
|
199
206
|
from myapp.registry import REGISTRY
|
|
@@ -203,19 +210,27 @@ app = create_agent_app(registry=REGISTRY, config=config)
|
|
|
203
210
|
```
|
|
204
211
|
|
|
205
212
|
**`__main__.py`**
|
|
213
|
+
|
|
206
214
|
```python
|
|
207
215
|
import uvicorn
|
|
208
216
|
from fred_runtime.app import load_agent_pod_config
|
|
209
217
|
|
|
210
218
|
def main():
|
|
211
219
|
config = load_agent_pod_config()
|
|
212
|
-
uvicorn.run(
|
|
220
|
+
uvicorn.run(
|
|
221
|
+
"myapp.main:app",
|
|
222
|
+
host=config.app.host,
|
|
223
|
+
port=config.app.port,
|
|
224
|
+
limit_concurrency=config.app.limit_concurrency,
|
|
225
|
+
reload=True,
|
|
226
|
+
)
|
|
213
227
|
|
|
214
228
|
if __name__ == "__main__":
|
|
215
229
|
main()
|
|
216
230
|
```
|
|
217
231
|
|
|
218
232
|
**`registry.py`**
|
|
233
|
+
|
|
219
234
|
```python
|
|
220
235
|
from fred_sdk.contracts.models import ReActAgentDefinition
|
|
221
236
|
|
|
@@ -232,11 +247,11 @@ See [fred-samples](https://github.com/ThalesGroup/fred) for a working reference
|
|
|
232
247
|
|
|
233
248
|
## Related packages
|
|
234
249
|
|
|
235
|
-
| Package
|
|
236
|
-
|
|
237
|
-
| `fred-core`
|
|
238
|
-
| `fred-sdk`
|
|
239
|
-
| `fred-runtime` | [pypi](https://pypi.org/project/fred-runtime/) | This package
|
|
250
|
+
| Package | PyPI | Role |
|
|
251
|
+
| -------------- | ---------------------------------------------- | ----------------------------------------------------------------------------- |
|
|
252
|
+
| `fred-core` | [pypi](https://pypi.org/project/fred-core/) | Pure utilities — logging, model factories, embeddings, portable observability |
|
|
253
|
+
| `fred-sdk` | [pypi](https://pypi.org/project/fred-sdk/) | Agent authoring — ReAct, Graph, tool contracts |
|
|
254
|
+
| `fred-runtime` | [pypi](https://pypi.org/project/fred-runtime/) | This package |
|
|
240
255
|
|
|
241
256
|
---
|
|
242
257
|
|
|
@@ -39,7 +39,7 @@ from typing import Any, Literal
|
|
|
39
39
|
|
|
40
40
|
import yaml
|
|
41
41
|
from fred_sdk.contracts.models import MCPServerConfiguration
|
|
42
|
-
from pydantic import BaseModel, ConfigDict, Field
|
|
42
|
+
from pydantic import BaseModel, ConfigDict, Field, model_validator
|
|
43
43
|
|
|
44
44
|
from .config import AgentPodConfig
|
|
45
45
|
|
|
@@ -114,6 +114,36 @@ class _McpCatalog(_CatalogFile):
|
|
|
114
114
|
version: Literal["v1"] = "v1"
|
|
115
115
|
servers: list[MCPServerConfiguration] = Field(default_factory=list)
|
|
116
116
|
|
|
117
|
+
@model_validator(mode="after")
|
|
118
|
+
def _reject_duplicate_server_ids(self) -> "_McpCatalog":
|
|
119
|
+
"""
|
|
120
|
+
Reject duplicate MCP server ids in one catalog.
|
|
121
|
+
|
|
122
|
+
Why this exists:
|
|
123
|
+
- the managed-agent contract now stores per-server config keyed by MCP
|
|
124
|
+
server id, so duplicates would make selection and config resolution
|
|
125
|
+
ambiguous and unsafe
|
|
126
|
+
|
|
127
|
+
How to use it:
|
|
128
|
+
- triggered automatically during `_McpCatalog.model_validate(...)`
|
|
129
|
+
|
|
130
|
+
Example:
|
|
131
|
+
- `load_mcp_catalog("./config/mcp_catalog.yaml")`
|
|
132
|
+
"""
|
|
133
|
+
|
|
134
|
+
seen: set[str] = set()
|
|
135
|
+
duplicates: list[str] = []
|
|
136
|
+
for server in self.servers:
|
|
137
|
+
if server.id in seen and server.id not in duplicates:
|
|
138
|
+
duplicates.append(server.id)
|
|
139
|
+
seen.add(server.id)
|
|
140
|
+
if duplicates:
|
|
141
|
+
duplicates_text = ", ".join(repr(server_id) for server_id in duplicates)
|
|
142
|
+
raise ValueError(
|
|
143
|
+
f"Duplicate MCP server id(s) in catalog: {duplicates_text}"
|
|
144
|
+
)
|
|
145
|
+
return self
|
|
146
|
+
|
|
117
147
|
|
|
118
148
|
def _load_yaml_mapping(path: Path) -> dict[str, Any]:
|
|
119
149
|
"""
|