dv-pipecat-flows 0.0.0.dev1644__tar.gz → 0.0.0.dev2087__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.
- dv_pipecat_flows-0.0.0.dev2087/.claude/skills/loki-logs/SKILL.md +121 -0
- dv_pipecat_flows-0.0.0.dev2087/.claude/skills/loki-logs/query-reference.md +113 -0
- dv_pipecat_flows-0.0.0.dev2087/.python-version +1 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/AGENTS.md +21 -0
- {dv_pipecat_flows-0.0.0.dev1644/src/dv_pipecat_flows.egg-info → dv_pipecat_flows-0.0.0.dev2087}/PKG-INFO +6 -2
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/README.md +2 -1
- dv_pipecat_flows-0.0.0.dev2087/engine_primitives_plan.md +128 -0
- dv_pipecat_flows-0.0.0.dev2087/evals/kb/.gitignore +2 -0
- dv_pipecat_flows-0.0.0.dev2087/evals/kb/README.md +213 -0
- dv_pipecat_flows-0.0.0.dev2087/evals/kb/RESULTS.md +133 -0
- dv_pipecat_flows-0.0.0.dev2087/evals/kb/UNIFIED_KB_BENCHMARKS.md +713 -0
- dv_pipecat_flows-0.0.0.dev2087/evals/kb/chunkers.py +179 -0
- dv_pipecat_flows-0.0.0.dev2087/evals/kb/contracts.py +128 -0
- dv_pipecat_flows-0.0.0.dev2087/evals/kb/datagen/generate_corpus.py +281 -0
- dv_pipecat_flows-0.0.0.dev2087/evals/kb/datagen/generate_dataset.py +413 -0
- dv_pipecat_flows-0.0.0.dev2087/evals/kb/datagen/generate_hybrid.py +181 -0
- dv_pipecat_flows-0.0.0.dev2087/evals/kb/datagen/templates/insurance.yaml +40 -0
- dv_pipecat_flows-0.0.0.dev2087/evals/kb/datasets/.gitignore +9 -0
- dv_pipecat_flows-0.0.0.dev2087/evals/kb/datasets/v1_hybrid/manifest.json +33 -0
- dv_pipecat_flows-0.0.0.dev2087/evals/kb/datasets/v1_retrieval/manifest.json +16 -0
- dv_pipecat_flows-0.0.0.dev2087/evals/kb/datasets/v1_retrieval_long/manifest.json +17 -0
- dv_pipecat_flows-0.0.0.dev2087/evals/kb/datasets/v1_synthetic/manifest.json +45 -0
- dv_pipecat_flows-0.0.0.dev2087/evals/kb/runners/run_filter_pick.py +515 -0
- dv_pipecat_flows-0.0.0.dev2087/evals/kb/runners/run_filter_scaling.py +286 -0
- dv_pipecat_flows-0.0.0.dev2087/evals/kb/runners/run_hybrid.py +205 -0
- dv_pipecat_flows-0.0.0.dev2087/evals/kb/runners/run_latency.py +232 -0
- dv_pipecat_flows-0.0.0.dev2087/evals/kb/runners/run_rerank.py +279 -0
- dv_pipecat_flows-0.0.0.dev2087/evals/kb/runners/run_retrieval.py +340 -0
- dv_pipecat_flows-0.0.0.dev2087/evals/kb/service/API.md +490 -0
- dv_pipecat_flows-0.0.0.dev2087/evals/kb/service/__init__.py +0 -0
- dv_pipecat_flows-0.0.0.dev2087/evals/kb/service/app.py +332 -0
- dv_pipecat_flows-0.0.0.dev2087/evals/kb/service/jobs.py +230 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/pyproject.toml +4 -1
- dv_pipecat_flows-0.0.0.dev2087/remote-asterisk-code/README.md +0 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087/src/dv_pipecat_flows.egg-info}/PKG-INFO +6 -2
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/src/dv_pipecat_flows.egg-info/SOURCES.txt +36 -1
- dv_pipecat_flows-0.0.0.dev2087/src/dv_pipecat_flows.egg-info/requires.txt +6 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/src/pipecat_flows/actions.py +47 -12
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/src/pipecat_flows/adapters.py +226 -0
- dv_pipecat_flows-0.0.0.dev2087/src/pipecat_flows/condition_evaluator.py +289 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/src/pipecat_flows/exceptions.py +39 -0
- dv_pipecat_flows-0.0.0.dev2087/src/pipecat_flows/flow_validator.py +145 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/src/pipecat_flows/manager.py +739 -2
- dv_pipecat_flows-0.0.0.dev2087/src/pipecat_flows/processors/__init__.py +7 -0
- dv_pipecat_flows-0.0.0.dev2087/src/pipecat_flows/processors/router_mode_guard.py +131 -0
- dv_pipecat_flows-0.0.0.dev2087/src/pipecat_flows/processors/speak_interruption_guard.py +84 -0
- dv_pipecat_flows-0.0.0.dev2087/src/pipecat_flows/processors/user_turn_observer.py +78 -0
- dv_pipecat_flows-0.0.0.dev2087/src/pipecat_flows/router_mode.py +347 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/src/pipecat_flows/types.py +180 -0
- dv_pipecat_flows-0.0.0.dev1644/.python-version +0 -1
- dv_pipecat_flows-0.0.0.dev1644/remote-asterisk-code/README.md +0 -307
- dv_pipecat_flows-0.0.0.dev1644/src/dv_pipecat_flows.egg-info/requires.txt +0 -3
- {dv_pipecat_flows-0.0.0.dev1644/.claude → dv_pipecat_flows-0.0.0.dev2087/.agents}/skills/loki-logs/SKILL.md +0 -0
- {dv_pipecat_flows-0.0.0.dev1644/.claude → dv_pipecat_flows-0.0.0.dev2087/.agents}/skills/loki-logs/query-reference.md +0 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/.gitattributes +0 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/.gitignore +0 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/.pre-commit-config.yaml +0 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/.readthedocs.yaml +0 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/CHANGELOG.md +0 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/CLAUDE.md +0 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/CONTRIBUTING.md +0 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/LICENSE +0 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/MANIFEST.in +0 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/dev-requirements.txt +0 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/docker-compose.dev.yml +0 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/.eslintrc.json +0 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/.prettierrc +0 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/css/tailwind.css +0 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/examples/food_ordering.json +0 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/examples/movie_explorer.json +0 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/examples/patient_intake.json +0 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/examples/restaurant_reservation.json +0 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/examples/travel_planner.json +0 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/favicon.png +0 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/favicon.svg +0 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/index.html +0 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/js/editor/canvas.js +0 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/js/editor/editorState.js +0 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/js/editor/sidePanel.js +0 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/js/editor/toolbar.js +0 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/js/main.js +0 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/js/nodes/baseNode.js +0 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/js/nodes/endNode.js +0 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/js/nodes/flowNode.js +0 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/js/nodes/functionNode.js +0 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/js/nodes/index.js +0 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/js/nodes/mergeNode.js +0 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/js/nodes/startNode.js +0 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/js/types.js +0 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/js/utils/export.js +0 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/js/utils/helpers.js +0 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/js/utils/import.js +0 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/js/utils/validation.js +0 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/jsdoc.json +0 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/package-lock.json +0 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/package.json +0 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/postcss.config.cjs +0 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/public/favicon.png +0 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/public/favicon.svg +0 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/tailwind.config.cjs +0 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/vercel.json +0 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/vite.config.js +0 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/env.example +0 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/images/food-ordering-flow.png +0 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/pipecat-flows.png +0 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/pipecat_upgrade.md +0 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/remote-asterisk-code/extensions.conf +0 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/remote-asterisk-code/rtp.conf +0 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/requirements.txt +0 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/scripts/check-pypi-package.py +0 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/scripts/fix-ruff.sh +0 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/scripts/pre-commit.sh +0 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/setup.cfg +0 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/src/dv_pipecat_flows.egg-info/dependency_links.txt +0 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/src/dv_pipecat_flows.egg-info/top_level.txt +0 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/src/pipecat_flows/__init__.py +0 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/src/pipecat_flows/data_extractor.py +0 -0
- {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/uv.lock +0 -0
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: loki-logs
|
|
3
|
+
description: Fetch and analyze pipecat application logs from Loki by call ID or call SID. Use when debugging call issues, investigating errors, or analyzing bot behavior for a specific call. Accepts a call_id (UUID) or call_sid (numeric string like 3341710001) and optional environment (staging/production).
|
|
4
|
+
argument-hint: <call_id|call_sid> [staging|production]
|
|
5
|
+
allowed-tools: Bash(curl *), Bash(jq *)
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Loki Logs Fetcher
|
|
9
|
+
|
|
10
|
+
Fetch logs from Loki for a specific pipecat call and analyze them.
|
|
11
|
+
|
|
12
|
+
## Parameters
|
|
13
|
+
|
|
14
|
+
- `$0` — **call_id or call_sid** (required): Either a UUID (e.g. `f3df923e-d535-4eff-a3c8-fefbae0e73bf`) or a numeric call SID string (e.g. `3341710001`)
|
|
15
|
+
- `$1` — **environment** (optional): `production` (default) or `staging`
|
|
16
|
+
|
|
17
|
+
## Instructions
|
|
18
|
+
|
|
19
|
+
When invoked, follow these steps:
|
|
20
|
+
|
|
21
|
+
### 1. Parse arguments
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
IDENTIFIER = $0
|
|
25
|
+
ENV = $1 (default: "production")
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
If `ENV` is `prod`, normalize it to `production`.
|
|
29
|
+
If `IDENTIFIER` is missing, ask the user for it.
|
|
30
|
+
|
|
31
|
+
Detect the identifier type:
|
|
32
|
+
- **UUID format** (contains hyphens, hex chars, e.g. `f3df923e-d535-...`): This is a `call_id`
|
|
33
|
+
- **Numeric string** (digits only, e.g. `3341710001`): This is a `call_sid`
|
|
34
|
+
|
|
35
|
+
Both work the same way in the Loki query — they are used as a substring match (`|=`) against the log lines.
|
|
36
|
+
|
|
37
|
+
### 2. Fetch logs from Loki
|
|
38
|
+
|
|
39
|
+
Use the Loki HTTP API at `http://35.154.72.110:3100` to query logs.
|
|
40
|
+
|
|
41
|
+
The LogQL query to use:
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
{application="pipecat", environment="<ENV>"} |= `<IDENTIFIER>` | json | level=~"(?i)DEBUG|INFO|WARNING|ERROR|FATAL" | line_format `{{.message}}`
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Execute this curl command (default time range: last 24 hours):
|
|
48
|
+
|
|
49
|
+
**Timezone note:** If the user provides a specific time or time range, treat it as **IST (Asia/Kolkata, UTC+5:30)**. Convert to UTC epoch before querying Loki.
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
# Calculate timestamps (nanoseconds) — default: last 24 hours
|
|
53
|
+
END=$(date +%s)000000000
|
|
54
|
+
START=$(( $(date +%s) - 86400 ))000000000
|
|
55
|
+
|
|
56
|
+
curl -s "http://35.154.72.110:3100/loki/api/v1/query_range" \
|
|
57
|
+
--data-urlencode "query={application=\"pipecat\", environment=\"<ENV>\"} |= \`<IDENTIFIER>\` | json | level=~\"(?i)DEBUG|INFO|WARNING|ERROR|FATAL\" | line_format \`{{.message}}\`" \
|
|
58
|
+
--data-urlencode "start=$START" \
|
|
59
|
+
--data-urlencode "end=$END" \
|
|
60
|
+
--data-urlencode "limit=5000" \
|
|
61
|
+
--data-urlencode "direction=forward" | jq .
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
If the result set is empty and the environment was `production`, suggest trying `staging` (and vice versa).
|
|
65
|
+
|
|
66
|
+
If the result set is empty for both, try expanding the time range to 48 hours.
|
|
67
|
+
|
|
68
|
+
### 3. Parse and display the logs
|
|
69
|
+
|
|
70
|
+
Extract the log lines from the Loki JSON response. The response structure is:
|
|
71
|
+
|
|
72
|
+
```json
|
|
73
|
+
{
|
|
74
|
+
"data": {
|
|
75
|
+
"result": [
|
|
76
|
+
{
|
|
77
|
+
"values": [
|
|
78
|
+
["<timestamp_ns>", "<log_line>"]
|
|
79
|
+
]
|
|
80
|
+
}
|
|
81
|
+
]
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Display the logs in chronological order (earliest first). Show:
|
|
87
|
+
- Timestamp (human-readable)
|
|
88
|
+
- Log level (if parseable)
|
|
89
|
+
- Message content
|
|
90
|
+
|
|
91
|
+
### 4. Analyze the logs
|
|
92
|
+
|
|
93
|
+
After displaying the logs, provide a brief analysis:
|
|
94
|
+
|
|
95
|
+
1. **Call timeline**: What happened during this call? (connected, greeted, conversation flow, ended)
|
|
96
|
+
2. **Errors/warnings**: Highlight any ERROR or WARNING level logs
|
|
97
|
+
3. **Tool calls**: List any function/tool calls made during the call
|
|
98
|
+
4. **TTS/STT activity**: Note any speech-related events
|
|
99
|
+
5. **Call outcome**: How did the call end? (normal hangup, error, transfer, timeout)
|
|
100
|
+
6. **Anomalies**: Flag anything unusual (long silences, repeated errors, unexpected state transitions)
|
|
101
|
+
|
|
102
|
+
### 5. Grafana link
|
|
103
|
+
|
|
104
|
+
Always provide a clickable Grafana Explore link for the user to view the logs in the browser:
|
|
105
|
+
|
|
106
|
+
```
|
|
107
|
+
http://35.154.72.110:3000/explore?schemaVersion=1&panes=%7B%221f1%22%3A%7B%22datasource%22%3A%22eeey6hiactdz4c%22%2C%22queries%22%3A%5B%7B%22datasource%22%3A%7B%22type%22%3A%22loki%22%2C%22uid%22%3A%22eeey6hiactdz4c%22%7D%2C%22direction%22%3A%22backward%22%2C%22editorMode%22%3A%22code%22%2C%22expr%22%3A%22%7Bapplication%3D%5C%22pipecat%5C%22%2C+environment%3D%5C%22<ENV>%5C%22%7D+%7C%3D+%60<IDENTIFIER>%60+%7C+json+%7C+level%3D%7E%5C%22%28%3Fi%29DEBUG%7CINFO%7CWARNING%7CERROR%7C+FATAL%5C%22+%7C+line_format+%60%7B%7B.message%7D%7D%60%22%2C%22queryType%22%3A%22range%22%2C%22refId%22%3A%22A%22%7D%5D%2C%22range%22%3A%7B%22from%22%3A%22now-6h%22%2C%22to%22%3A%22now%22%7D%2C%22compact%22%3Afalse%7D%7D&orgId=1
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Replace `<ENV>` and `<IDENTIFIER>` in the URL with the actual values (URL-encoded where needed).
|
|
111
|
+
|
|
112
|
+
## Troubleshooting
|
|
113
|
+
|
|
114
|
+
- If curl times out, the Loki instance may be under heavy load — retry with a shorter time range or lower limit.
|
|
115
|
+
- If you get no results, confirm the call_id is correct and try the other environment.
|
|
116
|
+
- For very old calls (>48h), increase the time range or ask the user for an approximate time window.
|
|
117
|
+
- All user-provided times are in **IST (UTC+5:30)** — convert to UTC epoch before querying.
|
|
118
|
+
|
|
119
|
+
## Reference
|
|
120
|
+
|
|
121
|
+
For LogQL query syntax and more filtering options, see [query-reference.md](query-reference.md).
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# LogQL Query Reference for Pipecat Logs
|
|
2
|
+
|
|
3
|
+
## Base Query Pattern
|
|
4
|
+
|
|
5
|
+
```logql
|
|
6
|
+
{application="pipecat", environment="<env>"} |= `<call_id>` | json | level=~"(?i)DEBUG|INFO|WARNING|ERROR|FATAL" | line_format `{{.message}}`
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Common Variations
|
|
10
|
+
|
|
11
|
+
### Filter by log level
|
|
12
|
+
|
|
13
|
+
**Errors only:**
|
|
14
|
+
```logql
|
|
15
|
+
{application="pipecat", environment="staging"} |= `<call_id>` | json | level=~"(?i)ERROR|FATAL" | line_format `{{.message}}`
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
**Warnings and above:**
|
|
19
|
+
```logql
|
|
20
|
+
{application="pipecat", environment="staging"} |= `<call_id>` | json | level=~"(?i)WARNING|ERROR|FATAL" | line_format `{{.message}}`
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### Filter by keyword
|
|
24
|
+
|
|
25
|
+
**LLM-related logs:**
|
|
26
|
+
```logql
|
|
27
|
+
{application="pipecat", environment="staging"} |= `<call_id>` | json | level=~"(?i)DEBUG|INFO|WARNING|ERROR|FATAL" | line_format `{{.message}}` |= "LLM"
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
**TTS-related logs:**
|
|
31
|
+
```logql
|
|
32
|
+
{application="pipecat", environment="staging"} |= `<call_id>` | json | line_format `{{.message}}` |= "TTS"
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
**Tool/function call logs:**
|
|
36
|
+
```logql
|
|
37
|
+
{application="pipecat", environment="staging"} |= `<call_id>` | json | line_format `{{.message}}` |~ "function|tool_call|generic_function"
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
**VAD/speech detection:**
|
|
41
|
+
```logql
|
|
42
|
+
{application="pipecat", environment="staging"} |= `<call_id>` | json | line_format `{{.message}}` |~ "VAD|speaking|speech|silence|idle"
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Search across all calls in an environment
|
|
46
|
+
|
|
47
|
+
**Recent errors (no call_id filter):**
|
|
48
|
+
```logql
|
|
49
|
+
{application="pipecat", environment="staging"} | json | level=~"(?i)ERROR|FATAL" | line_format `{{.message}}`
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
**By pod name:**
|
|
53
|
+
```logql
|
|
54
|
+
{application="pipecat", environment="staging", pod=~"pipecat-.*"} | json | line_format `{{.message}}`
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Loki API Endpoints
|
|
58
|
+
|
|
59
|
+
| Endpoint | Purpose |
|
|
60
|
+
|----------|---------|
|
|
61
|
+
| `GET /loki/api/v1/query_range` | Query logs over a time range |
|
|
62
|
+
| `GET /loki/api/v1/query` | Query logs at a single point in time |
|
|
63
|
+
| `GET /loki/api/v1/labels` | List all label names |
|
|
64
|
+
| `GET /loki/api/v1/label/<name>/values` | List values for a label |
|
|
65
|
+
| `GET /loki/api/v1/tail` | Stream logs via WebSocket |
|
|
66
|
+
|
|
67
|
+
### API Parameters for query_range
|
|
68
|
+
|
|
69
|
+
| Parameter | Description | Example |
|
|
70
|
+
|-----------|-------------|---------|
|
|
71
|
+
| `query` | LogQL query string | `{application="pipecat"}` |
|
|
72
|
+
| `start` | Start timestamp (nanoseconds or RFC3339) | `1609459200000000000` |
|
|
73
|
+
| `end` | End timestamp (nanoseconds or RFC3339) | `1609545600000000000` |
|
|
74
|
+
| `limit` | Max entries to return | `5000` |
|
|
75
|
+
| `direction` | Sort order: `forward` or `backward` | `forward` |
|
|
76
|
+
| `step` | Query resolution step (for metrics) | `60s` |
|
|
77
|
+
|
|
78
|
+
## Response Structure
|
|
79
|
+
|
|
80
|
+
```json
|
|
81
|
+
{
|
|
82
|
+
"status": "success",
|
|
83
|
+
"data": {
|
|
84
|
+
"resultType": "streams",
|
|
85
|
+
"result": [
|
|
86
|
+
{
|
|
87
|
+
"stream": {
|
|
88
|
+
"application": "pipecat",
|
|
89
|
+
"environment": "staging",
|
|
90
|
+
"level": "INFO"
|
|
91
|
+
},
|
|
92
|
+
"values": [
|
|
93
|
+
["1700000000000000000", "log message here"],
|
|
94
|
+
["1700000001000000000", "another log message"]
|
|
95
|
+
]
|
|
96
|
+
}
|
|
97
|
+
]
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Environment Values
|
|
103
|
+
|
|
104
|
+
| Environment | Label Value | Description |
|
|
105
|
+
|-------------|-------------|-------------|
|
|
106
|
+
| Staging | `staging` | Test/staging environment |
|
|
107
|
+
| Production | `production` | Live production environment |
|
|
108
|
+
|
|
109
|
+
## Infrastructure
|
|
110
|
+
|
|
111
|
+
- **Loki endpoint**: `http://35.154.72.110:3100`
|
|
112
|
+
- **Grafana UI**: `http://35.154.72.110:3000`
|
|
113
|
+
- **Loki datasource UID**: `eeey6hiactdz4c`
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.12.0
|
|
@@ -135,6 +135,27 @@ Example `call_config`:
|
|
|
135
135
|
- Flow tools fetch it via `s.get("bot_logger")` (e.g., `ringg-bot/utils/flow_tools/query_kb.py:28`). Prefer `bot_logger` when available, otherwise fall back to the global `logger`.
|
|
136
136
|
- Environment knobs for the custom logger (see `logger_config.py`): `ENVIRONMENT`, `LOGGER_NAME`, `GRAFANA_HOST` (enables Loki sink), and `LOG_DIRECTORY` (file sink path). In development, logs also go to console; in production, they rotate to `pipecat.log` and optionally ship to Loki.
|
|
137
137
|
- Interop: standard `logging` may appear in isolated places (e.g., Sphinx docs or third‑party adapters), but do not add `logging.getLogger(...)` or `basicConfig` in application modules. Stick to Loguru and the provided config.
|
|
138
|
+
|
|
139
|
+
### Message formatting — Loguru is **not** stdlib logging
|
|
140
|
+
|
|
141
|
+
Common gotcha: stdlib `logging.info("x=%s", val)` does printf-style lazy interpolation. Loguru does **not** — it ignores positional `args` and prints the format string verbatim. Use one of these instead:
|
|
142
|
+
|
|
143
|
+
```python
|
|
144
|
+
# Preferred: f-string (eager interpolation, simplest)
|
|
145
|
+
logger.info(f"call started call_id={call_id} agent={agent_id}")
|
|
146
|
+
|
|
147
|
+
# Or: Loguru's brace syntax with positional/keyword args
|
|
148
|
+
logger.info("call started call_id={} agent={}", call_id, agent_id)
|
|
149
|
+
logger.info("call started call_id={cid}", cid=call_id)
|
|
150
|
+
|
|
151
|
+
# WRONG — leaks raw "%s" into logs because Loguru does not consume *args
|
|
152
|
+
logger.info("call started call_id=%s agent=%s", call_id, agent_id)
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
If a log line shows up in Loki/console as `... call_id=%s ...` instead of the actual value, this is the cause — convert to f-string or `{}` style.
|
|
156
|
+
|
|
157
|
+
Bound context (via `logger.bind(call_id=...)`) is passed through `extra=` and is independent of the message format — it works the same regardless of which interpolation style you pick.
|
|
158
|
+
|
|
138
159
|
- Retry & timeout knobs live in `utils/pipeline.py` (idle handlers, hold detector) and `utils/stay_on_line_processor.py`. Update both place and config schema when adjusting thresholds.
|
|
139
160
|
|
|
140
161
|
## Working Guidelines for LLM Instructions
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dv-pipecat-flows
|
|
3
|
-
Version: 0.0.0.
|
|
3
|
+
Version: 0.0.0.dev2087
|
|
4
4
|
Summary: Conversation Flow management for Pipecat AI applications
|
|
5
5
|
License: BSD 2-Clause License
|
|
6
6
|
Project-URL: Source, https://github.com/pipecat-ai/pipecat-flows
|
|
@@ -18,6 +18,9 @@ License-File: LICENSE
|
|
|
18
18
|
Requires-Dist: dv-pipecat-ai>=0.0.85.dev0
|
|
19
19
|
Requires-Dist: loguru~=0.7.2
|
|
20
20
|
Requires-Dist: docstring_parser~=0.16
|
|
21
|
+
Requires-Dist: opentelemetry-api>=1.27.0
|
|
22
|
+
Requires-Dist: opentelemetry-sdk>=1.27.0
|
|
23
|
+
Requires-Dist: opentelemetry-exporter-otlp-proto-http>=1.27.0
|
|
21
24
|
Dynamic: license-file
|
|
22
25
|
|
|
23
26
|
<h1><div align="center">
|
|
@@ -148,7 +151,6 @@ Run specific test:
|
|
|
148
151
|
```bash
|
|
149
152
|
uv run pytest tests/test_state.py -k test_initialization
|
|
150
153
|
```
|
|
151
|
-
|
|
152
154
|
Run with coverage report:
|
|
153
155
|
|
|
154
156
|
```bash
|
|
@@ -306,3 +308,5 @@ We aim to review all contributions promptly and provide constructive feedback to
|
|
|
306
308
|
|
|
307
309
|
➡️ [Reach us on X](https://x.com/pipecat_ai)
|
|
308
310
|
|
|
311
|
+
|
|
312
|
+
|
|
@@ -126,7 +126,6 @@ Run specific test:
|
|
|
126
126
|
```bash
|
|
127
127
|
uv run pytest tests/test_state.py -k test_initialization
|
|
128
128
|
```
|
|
129
|
-
|
|
130
129
|
Run with coverage report:
|
|
131
130
|
|
|
132
131
|
```bash
|
|
@@ -284,3 +283,5 @@ We aim to review all contributions promptly and provide constructive feedback to
|
|
|
284
283
|
|
|
285
284
|
➡️ [Reach us on X](https://x.com/pipecat_ai)
|
|
286
285
|
|
|
286
|
+
|
|
287
|
+
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# Engine Primitives — Unified Implementation Plan
|
|
2
|
+
|
|
3
|
+
> Branch target: `feat/engine-primitives` in `dv-pipecat-flows`. Lands four primitives together: **auto_transition**, **condition_evaluator**, **router_mode_llm**, **llm_override + tool_choice**.
|
|
4
|
+
>
|
|
5
|
+
> Companion: [../new_calling_agent_backend/deterministic_agents_plan.md](../new_calling_agent_backend/deterministic_agents_plan.md) §6 Phase 1.
|
|
6
|
+
|
|
7
|
+
## 1. Shared touchpoints — edit once, not four times
|
|
8
|
+
|
|
9
|
+
| Touchpoint | File / line | Contributors | Unified shape & ordering |
|
|
10
|
+
|---|---|---|---|
|
|
11
|
+
| **`_set_node` dispatch block** | `manager.py:1012` | auto_transition, condition_evaluator, router_mode_llm | Introduce a single **dispatch pipeline** between `pre_actions` execution (1065) and `LLMRunFrame` emission (1165). Sequence: (a) `pre_actions` run; (b) `_apply_node_overrides` (now also handles `llm_override`); (c) `_process_data_extraction`; (d) **`_maybe_route_pure_code(node_id, node_config)`** which short-circuits if condition / auto-transition / router fires; (e) only if no short-circuit, continue to tools+context+`LLMRunFrame`. Single early-return point; each primitive contributes one helper. |
|
|
12
|
+
| **`NodeConfig` TypedDict** | `types.py:357` | all four | One PR adds `auto_transition`, `llm_mode`, `llm_override`, `router_branches`, `router_extract`, `router_unclear_node`, `router_max_unclear`, `router_exhausted_node`, `suppress_llm_text`, `forced_route_at_end_of_turn`, `tool_choice`, `conditions`, `router_default_next`. Plus supporting types (`AutoTransitionBranches`, `LLMOverride`, `RouterBranch`, `ExtractSpec`, `Condition`, `Rule`). All `NotRequired`; legacy nodes unaffected. |
|
|
13
|
+
| **`_apply_node_overrides`** | `manager.py:912` | llm_override (primary), router_mode_llm (consumer) | Add LLM-switch block mirroring the TTS pattern: snapshot active LLM in `node_runtime["_llm_restore"]`, queue `ManuallySwitchServiceFrame`. Router-mode reads the *already-resolved* `active_llm` rather than re-resolving — single resolution path. |
|
|
14
|
+
| **`format_functions` signature** | `adapters.py:77, 225, 418` | llm_override (tool_choice), router_mode_llm | New optional kwarg `tool_choice`. Each subclass returns a `(tools, native_tool_choice)` tuple. Router-mode reuses this when it chooses tool-shaped structured output (Anthropic / Bedrock-Claude); JSON-schema providers (OpenAI / Gemini) take the `response_format` path inside `run_router_completion`. |
|
|
15
|
+
| **`LLMSetToolsFrame` emission** | `manager.py:1277` | llm_override, router_mode_llm | Accept `tool_choice=...` kwarg; one emission site, consumed by aggregator. |
|
|
16
|
+
| **Idle-processor bracket** | `manager.py:1043 / 1176` | auto_transition, condition_evaluator | Both short-circuit paths re-emit `StartUserIdleProcessorFrame` before recursing so the recursive `_set_node` re-establishes the bracket cleanly. Encoded once in `_short_circuit_to(next_id)` helper. |
|
|
17
|
+
| **State + tool-result snapshot** | `FlowManager.__init__` | auto_transition (`_last_action_result`), condition_evaluator (`_pending_function_results`), router_mode_llm (`state["_router_attempts"]`) | All three live on `FlowManager`. Add a dedicated `self._primitive_state` namespace (dict) to keep them grouped and easy to clear on `cancel()`. |
|
|
18
|
+
| **Frame interruption observer** | manager.py (`UserInterruptedFrame` handler) | auto_transition (cancel pending), router_mode_llm (abort in-flight completion) | One observer extension sets cancellation flags consumed by both primitives. |
|
|
19
|
+
| **`flow_validator.py` (NEW)** | new file | all four | Single validator pass: rejects `post_actions` + `auto_transition`; `respond_immediately` + `auto_transition`; cycle without `router_max_unclear`; reserved extraction keys; `llm_override` with unknown provider; `tool_choice` with unsupported provider (warn, don't fail). |
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## 2. Implementation order (4 PRs on the branch, merged in sequence)
|
|
24
|
+
|
|
25
|
+
1. **Foundation (PR-1).** `types.py` additions + `flow_validator.py` skeleton + `exceptions.py` (`RouterParseError`, `RouterProviderError`). No behavior change. *Justification:* every later PR imports these; landing types first means PR-2/3/4 are pure feature wiring with no rebase pain.
|
|
26
|
+
2. **Adapter plumbing (PR-2).** `format_functions(..., tool_choice=...)` across all four adapters + `LLMSetToolsFrame` kwarg + `_apply_node_overrides` LLM-switch block. *Justification:* this is purely additive infrastructure; router-mode (PR-4) depends on it; auto-transition and condition-evaluator do not — so we can land and unit-test in isolation.
|
|
27
|
+
3. **Pure-code dispatchers (PR-3).** `condition_evaluator.py` module + `auto_transition` block + the unified `_maybe_route_pure_code` dispatcher in `_set_node`. *Justification:* both are LLM-free and verifiable with mocked frame queues; they exercise the new dispatch pipeline before we add the heavier router-mode path.
|
|
28
|
+
4. **Router-mode LLM (PR-4).** Per-adapter `run_router_completion` + `_run_router_node` + `RouterModeGuard` hook + unclear-loop state machine. *Justification:* heaviest, touches network + provider quirks; landing last means it inherits a stable dispatch contract and adapter shape.
|
|
29
|
+
|
|
30
|
+
Phase 1 of `../new_calling_agent_backend/deterministic_agents_plan.md` §6 maps to PR-1 + PR-2; Phase 2 picks up after PR-3.
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## 3. Per-file diff outline
|
|
35
|
+
|
|
36
|
+
| File | Change | ~LOC | Contributors |
|
|
37
|
+
|---|---|---|---|
|
|
38
|
+
| `src/pipecat_flows/types.py` | Add `AutoTransitionBranches`, `LLMOverride`, `RouterBranch`, `ExtractSpec`, `Rule`, `Condition`, extend `NodeConfig` with 12 new optional keys. | +110 | all four |
|
|
39
|
+
| `src/pipecat_flows/exceptions.py` | Add `RouterParseError`, `RouterProviderError`, `AutoTransitionDepthError`. | +20 | router, auto |
|
|
40
|
+
| `src/pipecat_flows/manager.py` | (a) `__init__` adds `_last_action_result`, `_pending_auto_transition_cancelled`, `_auto_transition_depth`, `_primitive_state`. (b) `_apply_node_overrides` LLM-switch block + restore-on-teardown. (c) New `_maybe_route_pure_code`, `_short_circuit_to`, `_await_pre_actions_complete`, `_resolve_auto_transition_target`, `_resolve_llm_from_switcher`, `_run_router_node`, `_handle_router_unclear`, `_parse_router_response`. (d) `_set_node` rewires dispatch sequence; only ~8 lines added inline (the rest are helper calls). (e) Interruption observer extension. | +280 / −12 | all four |
|
|
41
|
+
| `src/pipecat_flows/actions.py` | `_handle_function_action` (line 353) writes `flow_manager._last_action_result` (success/failure/value). Wrap existing try/except. | +25 | auto_transition |
|
|
42
|
+
| `src/pipecat_flows/adapters.py` | `format_functions` gets `tool_choice` kwarg in base + 3 subclasses; each returns `(tools, native_tool_choice)`. Add `run_router_completion` + `format_router_call` to each subclass (OpenAI JSON-schema, Anthropic tool-forced, Gemini `response_schema`, Bedrock dual-path). | +220 | llm_override, router |
|
|
43
|
+
| `src/pipecat_flows/data_extractor.py` | No changes (router-mode writes directly into `state`, sharing the same flat namespace contract). | 0 | — |
|
|
44
|
+
| `src/pipecat_flows/__init__.py` | Re-export new public types + `evaluate_conditions`. | +8 | all four |
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## 4. New files
|
|
49
|
+
|
|
50
|
+
- `src/pipecat_flows/condition_evaluator.py` — pure-function rule evaluator + variable resolver (no I/O, no manager refs).
|
|
51
|
+
- `src/pipecat_flows/flow_validator.py` — static graph validator invoked once at `FlowManager.__init__`; enforces primitive-combination rules and reserved keys.
|
|
52
|
+
- `src/pipecat_flows/router_mode.py` — schema builder, prompt builder, response parser, unclear-loop bookkeeping (keeps `manager.py` from ballooning further).
|
|
53
|
+
- `src/pipecat_flows/processors/router_mode_guard.py` — `FrameProcessor` subclass dropping `LLMTextFrame` etc. when `current_node_config.suppress_llm_text` is true. Owned by flows because the policy is per-node.
|
|
54
|
+
- `tests/conftest_primitives.py` — shared fixtures: `make_flow_manager(nodes, state=…, llm=FakeLLM())`, fake `LLMSwitcher`, fake adapter, frame-queue sink.
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## 5. Test strategy
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
tests/
|
|
62
|
+
conftest_primitives.py # shared fixtures
|
|
63
|
+
unit/
|
|
64
|
+
test_types_validation.py # NodeConfig keys, flow_validator rules
|
|
65
|
+
test_condition_evaluator.py # ~60 parametrised op cases (PR-3)
|
|
66
|
+
test_auto_transition_unit.py # str/branches, timeout, cancel, depth cap
|
|
67
|
+
test_router_parser.py # JSON, type coercion, unknown branch
|
|
68
|
+
test_adapters_tool_choice.py # per-provider native shape snapshots
|
|
69
|
+
test_adapters_router_completion.py # mocked HTTP per provider
|
|
70
|
+
test_apply_node_overrides_llm.py # switcher snapshot/restore
|
|
71
|
+
integration/
|
|
72
|
+
test_dispatch_pipeline.py # _set_node short-circuit ordering
|
|
73
|
+
test_auto_transition_pipeline.py # Speak→Speak, no LLMRunFrame, barge-in
|
|
74
|
+
test_condition_node_routing.py # state + tool-output routing
|
|
75
|
+
test_router_flow.py # 3 malformed → exhausted; provider timeout
|
|
76
|
+
test_router_mode_guard.py # text-frame suppression per-node
|
|
77
|
+
test_primitive_combinations.py # router → condition → auto chain
|
|
78
|
+
fixtures/
|
|
79
|
+
monica_flow.json # §7 below
|
|
80
|
+
mocked_provider_payloads/ # snapshot baselines
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
**Minimal FlowManager for unit tests** — `make_flow_manager(nodes, state=None, llm=None)` in `conftest_primitives.py`:
|
|
84
|
+
|
|
85
|
+
```python
|
|
86
|
+
def make_flow_manager(nodes, state=None, llm=None):
|
|
87
|
+
task = FakePipelineTask() # records queued frames
|
|
88
|
+
llm = llm or FakeLLM() # implements register_function + active_llm
|
|
89
|
+
fm = FlowManager(task=task, llm=llm,
|
|
90
|
+
flow_config={"initial_node": next(iter(nodes)), "nodes": nodes})
|
|
91
|
+
if state: fm.state.update(state)
|
|
92
|
+
return fm, task
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Backend smoke test lives at `../new_calling_agent_backend/tests/test_flow_lowering_primitives.py`: asserts `flow_lowering.py` emits the new keys (`auto_transition`, `llm_mode`, `conditions`, `llm_override`, `tool_choice`) only for the right node types.
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## 6. Top 5 risks
|
|
100
|
+
|
|
101
|
+
1. **Interruption races at the dispatch boundary.** Barge-in landing between `pre_actions` finishing and the short-circuit `_set_node` call could leave a half-updated `_current_node` and a stalled idle bracket. *Mitigation:* `_pending_auto_transition_cancelled` flag + `_ongoing_actions_finished_event.set()` in the interruption observer; integration test covers it.
|
|
102
|
+
2. **Provider feature gaps for structured output.** Bedrock-Llama/Titan don't support JSON-schema or forced tool_use; Gemini's `response_schema` has stricter subset of JSON-schema than OpenAI. *Mitigation:* per-adapter fallback ladder (native schema → tool-forced → prompt-engineered + validate-retry-once); validator warns at startup if `llm_override` selects a provider lacking router support.
|
|
103
|
+
3. **Dispatch ordering regressions.** Six things now happen between `pre_actions` and `LLMRunFrame`. Moving them silently breaks legacy generative nodes. *Mitigation:* `test_dispatch_pipeline.py` asserts exact frame-queue ordering on a vanilla LLM node; CI gate on this test.
|
|
104
|
+
4. **LLM-switch mid-generation.** `ManuallySwitchServiceFrame` on a node entry while previous node's response is still streaming corrupts the aggregator. *Mitigation:* defer override switch until `is_generating` is false; if router/auto short-circuit fired (no streaming), apply immediately. Add `test_apply_node_overrides_llm.py::test_switch_waits_for_generation_complete`.
|
|
105
|
+
5. **Auto-transition / router cycles.** Misconfigured graphs (A→A via auto, or router whose unclear_node loops back) can pin the call. *Mitigation:* `_auto_transition_depth` cap of 16, existing `_max_node_transitions` guard, and `flow_validator` rejects self-loops without a `router_max_unclear` counter; loud `FlowError` on exhaustion.
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## 7. Cred Monica integration end-to-end check
|
|
110
|
+
|
|
111
|
+
Once all four primitives land, scripted graph `tests/fixtures/monica_flow.json` (~14 Speak + 11 Hindi mirrors + 3 routers + 2 End — per `../new_calling_agent_backend/deterministic_agents_plan.md` §9.2) is the golden integration. Minimum verification driver `tests/integration/test_monica_e2e.py`:
|
|
112
|
+
|
|
113
|
+
1. **Greeting → terminal (happy path "agrees to pay")** — drives `greeting` (Speak with `auto_transition: classify_intent`), feeds a fake user turn "yes I'll pay", asserts `classify_intent` router (llm_mode=router, Haiku via `llm_override`) returns `{branch: "agrees_to_pay"}`, asserts `say_agrees` Speak fires with `auto_transition: end_success`. **No `LLMRunFrame` emitted across the whole 3-node chain.**
|
|
114
|
+
2. **Sensitive-reason branch** — drives `classify_intent` → `ask_reason` → `classify_reason` (router with extract) → `say_sensitive` → `end_success`. Assert extracted `reason_category="sensitive"` is in `state`.
|
|
115
|
+
3. **Unclear loop exhaustion** — feed two consecutive garbled replies to `classify_intent` with `router_max_unclear: 2`; assert traversal lands on `end_default` (exhausted_next).
|
|
116
|
+
4. **Hindi language switch** — `classify_intent` returns `{branch: "wants_hindi"}` + `extracted.language="hi"`; assert `ask_hindi_confirm` → `route_hindi_yesno` → `greeting_hi` chain executes with `overrides.tts.language="hi"` applied through `_apply_node_overrides`.
|
|
117
|
+
5. **Latency assertion** — using `FakePipelineTask`'s recorded timestamps, assert greeting → classify_intent → terminal Speak completes in < 100ms wall-clock with mocked LLM (the real bot target is < 0.9s; this checks the engine adds no extra hops). Pre-render is out of scope for this PR (Phase 3 in plan §6).
|
|
118
|
+
6. **Backward-compat regression** — re-run existing `tests/test_manager.py` and `tests/test_actions.py` unchanged; all green.
|
|
119
|
+
|
|
120
|
+
If all six pass, the engine side of §9 is shippable and the backend can begin Phase 2 (`flow_lowering.py` emitting these keys, already prototyped in the backend repo's `agent/commons/flow_lowering.py`).
|
|
121
|
+
|
|
122
|
+
Relevant absolute paths:
|
|
123
|
+
- `src/pipecat_flows/manager.py`
|
|
124
|
+
- `src/pipecat_flows/types.py`
|
|
125
|
+
- `src/pipecat_flows/adapters.py`
|
|
126
|
+
- `src/pipecat_flows/actions.py`
|
|
127
|
+
- `../new_calling_agent_backend/deterministic_agents_plan.md` §9
|
|
128
|
+
- `../new_calling_agent_backend/agent/commons/flow_lowering.py`
|