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.
Files changed (118) hide show
  1. dv_pipecat_flows-0.0.0.dev2087/.claude/skills/loki-logs/SKILL.md +121 -0
  2. dv_pipecat_flows-0.0.0.dev2087/.claude/skills/loki-logs/query-reference.md +113 -0
  3. dv_pipecat_flows-0.0.0.dev2087/.python-version +1 -0
  4. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/AGENTS.md +21 -0
  5. {dv_pipecat_flows-0.0.0.dev1644/src/dv_pipecat_flows.egg-info → dv_pipecat_flows-0.0.0.dev2087}/PKG-INFO +6 -2
  6. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/README.md +2 -1
  7. dv_pipecat_flows-0.0.0.dev2087/engine_primitives_plan.md +128 -0
  8. dv_pipecat_flows-0.0.0.dev2087/evals/kb/.gitignore +2 -0
  9. dv_pipecat_flows-0.0.0.dev2087/evals/kb/README.md +213 -0
  10. dv_pipecat_flows-0.0.0.dev2087/evals/kb/RESULTS.md +133 -0
  11. dv_pipecat_flows-0.0.0.dev2087/evals/kb/UNIFIED_KB_BENCHMARKS.md +713 -0
  12. dv_pipecat_flows-0.0.0.dev2087/evals/kb/chunkers.py +179 -0
  13. dv_pipecat_flows-0.0.0.dev2087/evals/kb/contracts.py +128 -0
  14. dv_pipecat_flows-0.0.0.dev2087/evals/kb/datagen/generate_corpus.py +281 -0
  15. dv_pipecat_flows-0.0.0.dev2087/evals/kb/datagen/generate_dataset.py +413 -0
  16. dv_pipecat_flows-0.0.0.dev2087/evals/kb/datagen/generate_hybrid.py +181 -0
  17. dv_pipecat_flows-0.0.0.dev2087/evals/kb/datagen/templates/insurance.yaml +40 -0
  18. dv_pipecat_flows-0.0.0.dev2087/evals/kb/datasets/.gitignore +9 -0
  19. dv_pipecat_flows-0.0.0.dev2087/evals/kb/datasets/v1_hybrid/manifest.json +33 -0
  20. dv_pipecat_flows-0.0.0.dev2087/evals/kb/datasets/v1_retrieval/manifest.json +16 -0
  21. dv_pipecat_flows-0.0.0.dev2087/evals/kb/datasets/v1_retrieval_long/manifest.json +17 -0
  22. dv_pipecat_flows-0.0.0.dev2087/evals/kb/datasets/v1_synthetic/manifest.json +45 -0
  23. dv_pipecat_flows-0.0.0.dev2087/evals/kb/runners/run_filter_pick.py +515 -0
  24. dv_pipecat_flows-0.0.0.dev2087/evals/kb/runners/run_filter_scaling.py +286 -0
  25. dv_pipecat_flows-0.0.0.dev2087/evals/kb/runners/run_hybrid.py +205 -0
  26. dv_pipecat_flows-0.0.0.dev2087/evals/kb/runners/run_latency.py +232 -0
  27. dv_pipecat_flows-0.0.0.dev2087/evals/kb/runners/run_rerank.py +279 -0
  28. dv_pipecat_flows-0.0.0.dev2087/evals/kb/runners/run_retrieval.py +340 -0
  29. dv_pipecat_flows-0.0.0.dev2087/evals/kb/service/API.md +490 -0
  30. dv_pipecat_flows-0.0.0.dev2087/evals/kb/service/__init__.py +0 -0
  31. dv_pipecat_flows-0.0.0.dev2087/evals/kb/service/app.py +332 -0
  32. dv_pipecat_flows-0.0.0.dev2087/evals/kb/service/jobs.py +230 -0
  33. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/pyproject.toml +4 -1
  34. dv_pipecat_flows-0.0.0.dev2087/remote-asterisk-code/README.md +0 -0
  35. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087/src/dv_pipecat_flows.egg-info}/PKG-INFO +6 -2
  36. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/src/dv_pipecat_flows.egg-info/SOURCES.txt +36 -1
  37. dv_pipecat_flows-0.0.0.dev2087/src/dv_pipecat_flows.egg-info/requires.txt +6 -0
  38. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/src/pipecat_flows/actions.py +47 -12
  39. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/src/pipecat_flows/adapters.py +226 -0
  40. dv_pipecat_flows-0.0.0.dev2087/src/pipecat_flows/condition_evaluator.py +289 -0
  41. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/src/pipecat_flows/exceptions.py +39 -0
  42. dv_pipecat_flows-0.0.0.dev2087/src/pipecat_flows/flow_validator.py +145 -0
  43. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/src/pipecat_flows/manager.py +739 -2
  44. dv_pipecat_flows-0.0.0.dev2087/src/pipecat_flows/processors/__init__.py +7 -0
  45. dv_pipecat_flows-0.0.0.dev2087/src/pipecat_flows/processors/router_mode_guard.py +131 -0
  46. dv_pipecat_flows-0.0.0.dev2087/src/pipecat_flows/processors/speak_interruption_guard.py +84 -0
  47. dv_pipecat_flows-0.0.0.dev2087/src/pipecat_flows/processors/user_turn_observer.py +78 -0
  48. dv_pipecat_flows-0.0.0.dev2087/src/pipecat_flows/router_mode.py +347 -0
  49. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/src/pipecat_flows/types.py +180 -0
  50. dv_pipecat_flows-0.0.0.dev1644/.python-version +0 -1
  51. dv_pipecat_flows-0.0.0.dev1644/remote-asterisk-code/README.md +0 -307
  52. dv_pipecat_flows-0.0.0.dev1644/src/dv_pipecat_flows.egg-info/requires.txt +0 -3
  53. {dv_pipecat_flows-0.0.0.dev1644/.claude → dv_pipecat_flows-0.0.0.dev2087/.agents}/skills/loki-logs/SKILL.md +0 -0
  54. {dv_pipecat_flows-0.0.0.dev1644/.claude → dv_pipecat_flows-0.0.0.dev2087/.agents}/skills/loki-logs/query-reference.md +0 -0
  55. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/.gitattributes +0 -0
  56. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/.gitignore +0 -0
  57. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/.pre-commit-config.yaml +0 -0
  58. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/.readthedocs.yaml +0 -0
  59. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/CHANGELOG.md +0 -0
  60. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/CLAUDE.md +0 -0
  61. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/CONTRIBUTING.md +0 -0
  62. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/LICENSE +0 -0
  63. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/MANIFEST.in +0 -0
  64. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/dev-requirements.txt +0 -0
  65. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/docker-compose.dev.yml +0 -0
  66. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/.eslintrc.json +0 -0
  67. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/.prettierrc +0 -0
  68. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/css/tailwind.css +0 -0
  69. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/examples/food_ordering.json +0 -0
  70. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/examples/movie_explorer.json +0 -0
  71. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/examples/patient_intake.json +0 -0
  72. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/examples/restaurant_reservation.json +0 -0
  73. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/examples/travel_planner.json +0 -0
  74. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/favicon.png +0 -0
  75. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/favicon.svg +0 -0
  76. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/index.html +0 -0
  77. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/js/editor/canvas.js +0 -0
  78. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/js/editor/editorState.js +0 -0
  79. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/js/editor/sidePanel.js +0 -0
  80. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/js/editor/toolbar.js +0 -0
  81. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/js/main.js +0 -0
  82. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/js/nodes/baseNode.js +0 -0
  83. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/js/nodes/endNode.js +0 -0
  84. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/js/nodes/flowNode.js +0 -0
  85. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/js/nodes/functionNode.js +0 -0
  86. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/js/nodes/index.js +0 -0
  87. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/js/nodes/mergeNode.js +0 -0
  88. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/js/nodes/startNode.js +0 -0
  89. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/js/types.js +0 -0
  90. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/js/utils/export.js +0 -0
  91. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/js/utils/helpers.js +0 -0
  92. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/js/utils/import.js +0 -0
  93. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/js/utils/validation.js +0 -0
  94. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/jsdoc.json +0 -0
  95. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/package-lock.json +0 -0
  96. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/package.json +0 -0
  97. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/postcss.config.cjs +0 -0
  98. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/public/favicon.png +0 -0
  99. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/public/favicon.svg +0 -0
  100. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/tailwind.config.cjs +0 -0
  101. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/vercel.json +0 -0
  102. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/editor/vite.config.js +0 -0
  103. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/env.example +0 -0
  104. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/images/food-ordering-flow.png +0 -0
  105. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/pipecat-flows.png +0 -0
  106. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/pipecat_upgrade.md +0 -0
  107. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/remote-asterisk-code/extensions.conf +0 -0
  108. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/remote-asterisk-code/rtp.conf +0 -0
  109. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/requirements.txt +0 -0
  110. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/scripts/check-pypi-package.py +0 -0
  111. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/scripts/fix-ruff.sh +0 -0
  112. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/scripts/pre-commit.sh +0 -0
  113. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/setup.cfg +0 -0
  114. {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
  115. {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
  116. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/src/pipecat_flows/__init__.py +0 -0
  117. {dv_pipecat_flows-0.0.0.dev1644 → dv_pipecat_flows-0.0.0.dev2087}/src/pipecat_flows/data_extractor.py +0 -0
  118. {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.dev1644
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`
@@ -0,0 +1,2 @@
1
+ # Eval-api job records — generated run output, regenerated per run.
2
+ runs/