fastworkflow 2.17.8__py3-none-any.whl → 2.17.10__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- fastworkflow/_workflows/command_metadata_extraction/parameter_extraction.py +81 -5
- fastworkflow/chat_session.py +102 -33
- fastworkflow/command_metadata_api.py +50 -0
- fastworkflow/intent_clarification_agent.py +132 -0
- fastworkflow/run_fastapi_mcp/README.md +58 -40
- fastworkflow/run_fastapi_mcp/__main__.py +197 -114
- fastworkflow/run_fastapi_mcp/conversation_store.py +4 -4
- fastworkflow/run_fastapi_mcp/jwt_manager.py +24 -14
- fastworkflow/run_fastapi_mcp/utils.py +116 -52
- fastworkflow/train/__main__.py +1 -1
- fastworkflow/utils/react.py +13 -1
- fastworkflow/utils/signatures.py +49 -31
- fastworkflow/workflow_agent.py +78 -4
- {fastworkflow-2.17.8.dist-info → fastworkflow-2.17.10.dist-info}/METADATA +1 -1
- {fastworkflow-2.17.8.dist-info → fastworkflow-2.17.10.dist-info}/RECORD +18 -17
- {fastworkflow-2.17.8.dist-info → fastworkflow-2.17.10.dist-info}/LICENSE +0 -0
- {fastworkflow-2.17.8.dist-info → fastworkflow-2.17.10.dist-info}/WHEEL +0 -0
- {fastworkflow-2.17.8.dist-info → fastworkflow-2.17.10.dist-info}/entry_points.txt +0 -0
|
@@ -5,7 +5,7 @@ HTTP + MCP interface for FastWorkflow workflows with synchronous and streaming e
|
|
|
5
5
|
## Overview
|
|
6
6
|
|
|
7
7
|
This service exposes FastWorkflow workflows as REST endpoints and as MCP tools, enabling clients to:
|
|
8
|
-
- Initialize workflow sessions per
|
|
8
|
+
- Initialize workflow sessions per channel
|
|
9
9
|
- Submit natural language queries (agent mode)
|
|
10
10
|
- Execute deterministic commands (assistant mode)
|
|
11
11
|
- Perform explicit actions
|
|
@@ -14,8 +14,8 @@ This service exposes FastWorkflow workflows as REST endpoints and as MCP tools,
|
|
|
14
14
|
|
|
15
15
|
## Architecture
|
|
16
16
|
|
|
17
|
-
- **Session Management**: In-memory `
|
|
18
|
-
- **Persistence**: Rdict-backed conversation storage (one DB file per
|
|
17
|
+
- **Session Management**: In-memory `ChannelSessionManager` with per-channel `ChatSession` instances
|
|
18
|
+
- **Persistence**: Rdict-backed conversation storage (one DB file per channel)
|
|
19
19
|
- **Execution**: Synchronous turn-based processing with queue-based communication
|
|
20
20
|
- **Tracing**: Traces are collected by default and included in synchronous responses or emitted incrementally during streaming
|
|
21
21
|
- **Streaming (REST)**: `/invoke_agent_stream` supports Streamable HTTP via NDJSON by default and SSE when requested in REST initialize
|
|
@@ -50,27 +50,25 @@ Configure in your environment (loaded at process startup via CLI args or env loa
|
|
|
50
50
|
| `--expect_encrypted_jwt` | Enable full JWT signature verification (pass flag to require signed tokens) | No | False (no verification by default) |
|
|
51
51
|
|
|
52
52
|
Notes:
|
|
53
|
-
- Conversation DBs are stored under `SPEEDDICT_FOLDERNAME/
|
|
53
|
+
- Conversation DBs are stored under `SPEEDDICT_FOLDERNAME/channel_conversations` (directory is auto-created).
|
|
54
54
|
- `/conversations` now accepts a `limit` query parameter (default `20`).
|
|
55
55
|
- Shutdown waits up to 30 seconds for active turns (hard-coded).
|
|
56
56
|
|
|
57
|
-
##
|
|
57
|
+
## Auth Modes
|
|
58
58
|
|
|
59
|
-
###
|
|
60
|
-
|
|
59
|
+
### Trusted Mode (default): No Signature Verification
|
|
60
|
+
When `--expect_encrypted_jwt` is NOT set (trusted environments), the service still creates and returns JWT tokens from `/initialize`, but signature verification is disabled. Clients must include `Authorization: Bearer <access_token>` on subsequent requests.
|
|
61
61
|
|
|
62
62
|
```bash
|
|
63
63
|
uvicorn services.run_fastapi.main:app --workflow_path /path/to/workflow
|
|
64
64
|
```
|
|
65
65
|
|
|
66
|
-
|
|
67
|
-
-
|
|
68
|
-
-
|
|
69
|
-
-
|
|
66
|
+
Notes (trusted mode):
|
|
67
|
+
- `/initialize` returns access/refresh tokens and, if a startup command/action is provided, also returns the startup `CommandOutput`.
|
|
68
|
+
- Subsequent endpoints require `Authorization: Bearer <access_token>`.
|
|
69
|
+
- Traces include `user_id` when available (from JWT `uid` claim).
|
|
70
70
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
### Secure Mode: Enable Signature Verification
|
|
71
|
+
### Secure Mode: Signed JWTs with Verification
|
|
74
72
|
For production deployments requiring full RSA signature verification:
|
|
75
73
|
|
|
76
74
|
```bash
|
|
@@ -78,13 +76,14 @@ uvicorn services.run_fastapi.main:app --workflow_path /path/to/workflow --expect
|
|
|
78
76
|
```
|
|
79
77
|
|
|
80
78
|
**Secure mode** (with `--expect_encrypted_jwt` flag):
|
|
81
|
-
-
|
|
82
|
-
-
|
|
79
|
+
- `/initialize` issues access/refresh tokens. Subsequent endpoints require `Authorization: Bearer <token>`.
|
|
80
|
+
- JWT claims include `sub` (channel_id) and `uid` (user_id when provided).
|
|
81
|
+
- Tokens are verified (signature, expiry, audience/issuer). Invalid or expired tokens are rejected.
|
|
83
82
|
- Recommended for production deployments in untrusted environments
|
|
84
83
|
|
|
85
84
|
### Token Access in Workflow Context
|
|
86
85
|
|
|
87
|
-
JWT tokens are
|
|
86
|
+
In secure mode, JWT tokens are passed to workflows via `workflow_context['http_bearer_token']` to support authenticated upstream calls. In trusted mode, tokens are not created/returned and `http_bearer_token` is absent.
|
|
88
87
|
|
|
89
88
|
**Important notes:**
|
|
90
89
|
- The token is **only available to authenticated endpoints** (those using `get_session_and_ensure_runtime` dependency)
|
|
@@ -100,7 +99,7 @@ JWT tokens are automatically passed to workflows via the `workflow_context` para
|
|
|
100
99
|
|
|
101
100
|
```python
|
|
102
101
|
# In workflow code
|
|
103
|
-
workflow_context = self._context
|
|
102
|
+
workflow_context = self._context
|
|
104
103
|
bearer_token = workflow_context.get('http_bearer_token')
|
|
105
104
|
|
|
106
105
|
# Use token for API calls
|
|
@@ -111,39 +110,49 @@ response = requests.get("https://api.example.com/data", headers=headers)
|
|
|
111
110
|
## API Endpoints (REST)
|
|
112
111
|
|
|
113
112
|
### `POST /initialize`
|
|
114
|
-
Initialize a session for a
|
|
113
|
+
Initialize a session for a channel. Workflow configuration is loaded at server startup from CLI args/env.
|
|
115
114
|
|
|
116
115
|
**Request:**
|
|
117
116
|
```json
|
|
118
117
|
{
|
|
119
|
-
"
|
|
120
|
-
"
|
|
118
|
+
"channel_id": "channel-123",
|
|
119
|
+
"user_id": "user-9",
|
|
120
|
+
"stream_format": "ndjson",
|
|
121
|
+
"startup_command": "load_workflow ...",
|
|
122
|
+
"startup_action": {
|
|
123
|
+
"command_name": "find_orders",
|
|
124
|
+
"parameters": {"channel_id": 42}
|
|
125
|
+
}
|
|
121
126
|
}
|
|
122
127
|
```
|
|
123
128
|
|
|
124
|
-
**
|
|
129
|
+
**Rules:**
|
|
130
|
+
- `channel_id` is required.
|
|
131
|
+
- Exactly one of `startup_command` or `startup_action` may be provided (or neither).
|
|
132
|
+
- If startup is provided, `user_id` is required and recorded in the initial trace.
|
|
125
133
|
- `stream_format` controls REST streaming format for `/invoke_agent_stream` (NDJSON default, SSE optional).
|
|
126
|
-
- Workflow configuration is loaded at server startup from CLI args/env, not from the request.
|
|
127
134
|
|
|
128
135
|
**Response:**
|
|
129
136
|
```json
|
|
130
137
|
{
|
|
131
|
-
"access_token": "
|
|
132
|
-
"refresh_token": "
|
|
138
|
+
"access_token": "eyJhbGci...",
|
|
139
|
+
"refresh_token": "eyJhbGci...",
|
|
133
140
|
"token_type": "bearer",
|
|
134
|
-
"expires_in": 3600
|
|
141
|
+
"expires_in": 3600,
|
|
142
|
+
"startup_output": { /* CommandOutput, present only if startup was executed */ }
|
|
135
143
|
}
|
|
136
|
-
|
|
137
144
|
```
|
|
138
145
|
|
|
139
146
|
### `POST /invoke_agent`
|
|
140
147
|
Submit a natural language query for agentic processing.
|
|
141
148
|
|
|
149
|
+
**Headers:**
|
|
150
|
+
- `Authorization: Bearer <access_token>` (JWT contains `sub` for channel_id and optional `uid` for user_id)
|
|
151
|
+
|
|
142
152
|
**Request:**
|
|
143
153
|
```json
|
|
144
154
|
{
|
|
145
|
-
"
|
|
146
|
-
"user_query": "find orders for user 42",
|
|
155
|
+
"user_query": "find orders for channel 42",
|
|
147
156
|
"timeout_seconds": 60
|
|
148
157
|
}
|
|
149
158
|
```
|
|
@@ -153,7 +162,7 @@ Submit a natural language query for agentic processing.
|
|
|
153
162
|
{
|
|
154
163
|
"command_responses": [
|
|
155
164
|
{
|
|
156
|
-
"response": "Found 3 orders for
|
|
165
|
+
"response": "Found 3 orders for channel 42",
|
|
157
166
|
"success": true,
|
|
158
167
|
"artifacts": {},
|
|
159
168
|
"next_actions": [],
|
|
@@ -163,7 +172,7 @@ Submit a natural language query for agentic processing.
|
|
|
163
172
|
"workflow_name": "default_workflow",
|
|
164
173
|
"context": "Order management context",
|
|
165
174
|
"command_name": "find_orders",
|
|
166
|
-
"command_parameters": "
|
|
175
|
+
"command_parameters": "channel_id=42",
|
|
167
176
|
"traces": [...]
|
|
168
177
|
}
|
|
169
178
|
```
|
|
@@ -176,12 +185,15 @@ Same request/response format as `/invoke_agent`.
|
|
|
176
185
|
### `POST /perform_action`
|
|
177
186
|
Execute a specific workflow action directly (bypasses parameter extraction).
|
|
178
187
|
|
|
188
|
+
**Headers:**
|
|
189
|
+
- `Authorization: Bearer <access_token>` (JWT contains `sub` for channel_id and optional `uid` for user_id)
|
|
190
|
+
|
|
179
191
|
**Request:**
|
|
180
192
|
```json
|
|
181
193
|
{
|
|
182
194
|
"action": {
|
|
183
195
|
"command_name": "find_orders",
|
|
184
|
-
"parameters": {"
|
|
196
|
+
"parameters": {"channel_id": 42}
|
|
185
197
|
},
|
|
186
198
|
"timeout_seconds": 60
|
|
187
199
|
}
|
|
@@ -195,6 +207,8 @@ Stream trace events and final `CommandOutput` via Streamable HTTP:
|
|
|
195
207
|
- NDJSON (default; `Content-Type: application/x-ndjson`)
|
|
196
208
|
- SSE (when REST `stream_format` is set to `sse`; `Content-Type: text/event-stream`)
|
|
197
209
|
|
|
210
|
+
**Headers:** Same as `/invoke_agent`.
|
|
211
|
+
|
|
198
212
|
## Conversation Management (REST)
|
|
199
213
|
|
|
200
214
|
### `POST /new_conversation`
|
|
@@ -212,8 +226,8 @@ Persist current conversation and start a new one.
|
|
|
212
226
|
}
|
|
213
227
|
```
|
|
214
228
|
|
|
215
|
-
### `GET /conversations?
|
|
216
|
-
List conversations for a
|
|
229
|
+
### `GET /conversations?channel_id={channel_id}&limit=20`
|
|
230
|
+
List conversations for a channel (most recent first). `limit` is optional; defaults to `20`.
|
|
217
231
|
|
|
218
232
|
**Response:**
|
|
219
233
|
```json
|
|
@@ -277,7 +291,7 @@ Export all conversations to JSONL.
|
|
|
277
291
|
import requests
|
|
278
292
|
|
|
279
293
|
resp = requests.post("http://localhost:8000/initialize", json={
|
|
280
|
-
"
|
|
294
|
+
"channel_id": "alice",
|
|
281
295
|
"stream_format": "ndjson"
|
|
282
296
|
})
|
|
283
297
|
print(resp.json()) # {"access_token": "...", "refresh_token": "...", "token_type": "bearer", "expires_in": 3600}
|
|
@@ -287,7 +301,7 @@ print(resp.json()) # {"access_token": "...", "refresh_token": "...", "token_typ
|
|
|
287
301
|
```python
|
|
288
302
|
# First get a token from /initialize
|
|
289
303
|
init_resp = requests.post("http://localhost:8000/initialize", json={
|
|
290
|
-
"
|
|
304
|
+
"channel_id": "alice",
|
|
291
305
|
"stream_format": "ndjson"
|
|
292
306
|
})
|
|
293
307
|
token_data = init_resp.json()
|
|
@@ -297,7 +311,7 @@ access_token = token_data["access_token"]
|
|
|
297
311
|
resp = requests.post("http://localhost:8000/invoke_agent",
|
|
298
312
|
headers={"Authorization": f"Bearer {access_token}"},
|
|
299
313
|
json={
|
|
300
|
-
"
|
|
314
|
+
"channel_query": "list all channels",
|
|
301
315
|
"timeout_seconds": 30
|
|
302
316
|
}
|
|
303
317
|
)
|
|
@@ -308,7 +322,8 @@ print(result.get("traces"))
|
|
|
308
322
|
|
|
309
323
|
### MCP Quickstart
|
|
310
324
|
- Mount is available at `/mcp` (auto-exposed by fastapi_mcp).
|
|
311
|
-
- MCP clients use pre-configured long-lived access tokens (generated via `/admin/generate_mcp_token`).
|
|
325
|
+
- In secure mode, MCP clients use pre-configured long-lived access tokens (generated via `/admin/generate_mcp_token`).
|
|
326
|
+
- In trusted mode, clients must send `Authorization: Bearer <token>`; the JWT `sub` claim carries the `channel_id`.
|
|
312
327
|
- No need for initialize or refresh_token tools in MCP context.
|
|
313
328
|
|
|
314
329
|
MCP invoke agent (streaming):
|
|
@@ -319,14 +334,14 @@ curl -N -X POST http://localhost:8000/mcp/invoke_agent \
|
|
|
319
334
|
-H 'Content-Type: application/json' \
|
|
320
335
|
-H 'Accept: application/x-ndjson' \
|
|
321
336
|
-H 'Authorization: Bearer <your-mcp-token>' \
|
|
322
|
-
-d '{"
|
|
337
|
+
-d '{"channel_query":"find orders for channel 42","timeout_seconds":60}'
|
|
323
338
|
|
|
324
339
|
# SSE (if stream_format was set to "sse" during MCP setup)
|
|
325
340
|
curl -N -X POST http://localhost:8000/mcp/invoke_agent \
|
|
326
341
|
-H 'Content-Type: application/json' \
|
|
327
342
|
-H 'Accept: text/event-stream' \
|
|
328
343
|
-H 'Authorization: Bearer <your-mcp-token>' \
|
|
329
|
-
-d '{"
|
|
344
|
+
-d '{"channel_query":"find orders for channel 42","timeout_seconds":60}'
|
|
330
345
|
```
|
|
331
346
|
|
|
332
347
|
### MCP Prompts
|
|
@@ -345,6 +360,9 @@ See [`tests/`](../../tests/) for unit and integration tests.
|
|
|
345
360
|
- Timeout behavior (504 on no output)
|
|
346
361
|
- Conversation persistence and listing
|
|
347
362
|
- Feedback attachment
|
|
363
|
+
- Initialize with startup command/action returns `startup_output` and records conversation
|
|
364
|
+
- Both trusted mode return tokens; secure mode tokens are encrypted
|
|
365
|
+
- Traces include `user_id` and `raw_command`
|
|
348
366
|
|
|
349
367
|
## Future Enhancements
|
|
350
368
|
|