dv-pipecat-flows 0.0.22.dev1487__tar.gz → 0.0.22.dev1491__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.22.dev1487/src/dv_pipecat_flows.egg-info → dv_pipecat_flows-0.0.22.dev1491}/PKG-INFO +1 -1
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491/src/dv_pipecat_flows.egg-info}/PKG-INFO +1 -1
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/src/pipecat_flows/manager.py +238 -75
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/.agents/skills/loki-logs/SKILL.md +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/.agents/skills/loki-logs/query-reference.md +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/.claude/skills/loki-logs/SKILL.md +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/.claude/skills/loki-logs/query-reference.md +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/.gitattributes +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/.gitignore +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/.pre-commit-config.yaml +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/.python-version +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/.readthedocs.yaml +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/AGENTS.md +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/CHANGELOG.md +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/CLAUDE.md +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/CONTRIBUTING.md +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/LICENSE +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/MANIFEST.in +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/README.md +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/dev-requirements.txt +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/docker-compose.dev.yml +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/editor/.eslintrc.json +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/editor/.prettierrc +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/editor/css/tailwind.css +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/editor/examples/food_ordering.json +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/editor/examples/movie_explorer.json +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/editor/examples/patient_intake.json +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/editor/examples/restaurant_reservation.json +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/editor/examples/travel_planner.json +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/editor/favicon.png +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/editor/favicon.svg +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/editor/index.html +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/editor/js/editor/canvas.js +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/editor/js/editor/editorState.js +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/editor/js/editor/sidePanel.js +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/editor/js/editor/toolbar.js +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/editor/js/main.js +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/editor/js/nodes/baseNode.js +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/editor/js/nodes/endNode.js +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/editor/js/nodes/flowNode.js +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/editor/js/nodes/functionNode.js +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/editor/js/nodes/index.js +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/editor/js/nodes/mergeNode.js +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/editor/js/nodes/startNode.js +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/editor/js/types.js +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/editor/js/utils/export.js +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/editor/js/utils/helpers.js +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/editor/js/utils/import.js +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/editor/js/utils/validation.js +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/editor/jsdoc.json +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/editor/package-lock.json +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/editor/package.json +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/editor/postcss.config.cjs +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/editor/public/favicon.png +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/editor/public/favicon.svg +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/editor/tailwind.config.cjs +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/editor/vercel.json +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/editor/vite.config.js +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/engine_primitives_plan.md +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/env.example +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/images/food-ordering-flow.png +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/pipecat-flows.png +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/pipecat_upgrade.md +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/pyproject.toml +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/remote-asterisk-code/README.md +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/remote-asterisk-code/extensions.conf +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/remote-asterisk-code/rtp.conf +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/requirements.txt +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/scripts/check-pypi-package.py +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/scripts/fix-ruff.sh +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/scripts/pre-commit.sh +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/setup.cfg +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/src/dv_pipecat_flows.egg-info/SOURCES.txt +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/src/dv_pipecat_flows.egg-info/dependency_links.txt +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/src/dv_pipecat_flows.egg-info/requires.txt +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/src/dv_pipecat_flows.egg-info/top_level.txt +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/src/pipecat_flows/__init__.py +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/src/pipecat_flows/actions.py +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/src/pipecat_flows/adapters.py +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/src/pipecat_flows/condition_evaluator.py +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/src/pipecat_flows/exceptions.py +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/src/pipecat_flows/flow_validator.py +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/src/pipecat_flows/processors/__init__.py +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/src/pipecat_flows/processors/router_mode_guard.py +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/src/pipecat_flows/processors/speak_interruption_guard.py +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/src/pipecat_flows/processors/user_turn_observer.py +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/src/pipecat_flows/router_mode.py +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/src/pipecat_flows/types.py +0 -0
- {dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/uv.lock +0 -0
{dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/src/pipecat_flows/manager.py
RENAMED
|
@@ -48,7 +48,7 @@ from typing import (
|
|
|
48
48
|
|
|
49
49
|
from loguru import logger
|
|
50
50
|
from utils.tracking_helpers import start_tracking, complete_tracking
|
|
51
|
-
from utils.collect_normalizers import normalize_collect_value
|
|
51
|
+
from utils.collect_normalizers import is_repeat_request, normalize_collect_value
|
|
52
52
|
from utils.collect_prompts import collect_prompt
|
|
53
53
|
from pipecat.frames.frames import (
|
|
54
54
|
DTMFUpdateSettingsFrame,
|
|
@@ -2149,6 +2149,8 @@ In all of these cases, you can provide a `name` in your new node's config for de
|
|
|
2149
2149
|
system_prompt: Optional[str] = None,
|
|
2150
2150
|
context_prefix: Optional[List[Dict[str, Any]]] = None,
|
|
2151
2151
|
enum_values: Optional[List[str]] = None,
|
|
2152
|
+
since_ts: Optional[float] = None,
|
|
2153
|
+
with_reply: bool = False,
|
|
2152
2154
|
) -> Optional[str]:
|
|
2153
2155
|
"""Wait for the caller's spoken reply and extract a single value from it
|
|
2154
2156
|
via a constrained LLM call — the same primitive the LLM router uses
|
|
@@ -2158,9 +2160,12 @@ In all of these cases, you can provide a `name` in your new node's config for de
|
|
|
2158
2160
|
``context_prefix`` lets a caller prepend grounding messages (e.g. the
|
|
2159
2161
|
read-back question the confirm is about) ahead of the caller's latest
|
|
2160
2162
|
turn, and ``system_prompt`` overrides the default extraction instruction.
|
|
2163
|
+
``since_ts`` reads a reply that ALREADY committed (e.g. the caller's
|
|
2164
|
+
rejection of a read-back) instead of waiting for a new turn — pass it
|
|
2165
|
+
with ``timeout_s=0`` to re-extract a correction from the denial.
|
|
2161
2166
|
"""
|
|
2162
2167
|
observer = self._user_turn_observer
|
|
2163
|
-
entry_ts = time.monotonic()
|
|
2168
|
+
entry_ts = since_ts if since_ts is not None else time.monotonic()
|
|
2164
2169
|
if observer is not None and timeout_s > 0:
|
|
2165
2170
|
# Wait for the caller's reply to COMMIT, and stay PATIENT while they're
|
|
2166
2171
|
# still mid-utterance, so we read their finished answer (e.g. a
|
|
@@ -2186,7 +2191,24 @@ In all of these cases, you can provide a `name` in your new node's config for de
|
|
|
2186
2191
|
value_spec: Dict[str, Any] = {"type": "string", "description": description}
|
|
2187
2192
|
if enum_values:
|
|
2188
2193
|
value_spec = {"type": "enum", "values": list(enum_values), "description": description}
|
|
2189
|
-
|
|
2194
|
+
extract_spec: Dict[str, Any] = {"value": value_spec}
|
|
2195
|
+
if with_reply:
|
|
2196
|
+
# Same hybrid contract as the digit extractor: when the caller says
|
|
2197
|
+
# something conversational instead of the value, the model answers it
|
|
2198
|
+
# on-topic in `reply` (we speak that) and leaves `value` empty. The field
|
|
2199
|
+
# description below is the instruction — the system prompt stays untouched.
|
|
2200
|
+
self._collect_reply = ""
|
|
2201
|
+
extract_spec["reply"] = {
|
|
2202
|
+
"type": "string",
|
|
2203
|
+
"description": (
|
|
2204
|
+
"Empty whenever the caller gave the value. ONLY when they gave no "
|
|
2205
|
+
"value and instead said something conversational (a question, a "
|
|
2206
|
+
"hesitation, an objection), a SHORT reply in their language that "
|
|
2207
|
+
"answers in ONE sentence and then asks again for it. Stay on topic; "
|
|
2208
|
+
"for anything unrelated give a one-line redirect; make no promises."
|
|
2209
|
+
),
|
|
2210
|
+
}
|
|
2211
|
+
schema = build_router_response_schema([], extract_spec)
|
|
2190
2212
|
|
|
2191
2213
|
deadline = entry_ts + timeout_s if timeout_s > 0 else entry_ts
|
|
2192
2214
|
last_value: Optional[str] = None
|
|
@@ -2244,6 +2266,9 @@ In all of these cases, you can provide a `name` in your new node's config for de
|
|
|
2244
2266
|
value = (extracted or {}).get("value")
|
|
2245
2267
|
if isinstance(value, str) and value.strip():
|
|
2246
2268
|
last_value = value
|
|
2269
|
+
if with_reply:
|
|
2270
|
+
reply_val = (extracted or {}).get("reply")
|
|
2271
|
+
self._collect_reply = reply_val.strip() if isinstance(reply_val, str) else ""
|
|
2247
2272
|
# No observer (unit tests) → single shot. Otherwise re-extract only if
|
|
2248
2273
|
# the caller said MORE during the call or is still speaking, and time
|
|
2249
2274
|
# remains.
|
|
@@ -2362,6 +2387,7 @@ In all of these cases, you can provide a `name` in your new node's config for de
|
|
|
2362
2387
|
# can never trap the call in the node (the activity-aware wait below would
|
|
2363
2388
|
# otherwise reset forever).
|
|
2364
2389
|
_MAX_CAPTURE_SECONDS = 90.0
|
|
2390
|
+
_MAX_COLLECT_REPLIES = 5 # conversational (non-digit) LLM replies before falling back
|
|
2365
2391
|
|
|
2366
2392
|
def _caller_is_speaking(self) -> bool:
|
|
2367
2393
|
"""True while the caller has an IN-PROGRESS utterance — they started more
|
|
@@ -2410,6 +2436,8 @@ In all of these cases, you can provide a `name` in your new node's config for de
|
|
|
2410
2436
|
Returns digits 0-9 only, or "" if no digits / on error (degrades to a
|
|
2411
2437
|
re-ask).
|
|
2412
2438
|
"""
|
|
2439
|
+
self._collect_readback = "" # grouped, language-matched read-back for the confirm
|
|
2440
|
+
self._collect_reply = "" # LLM free reply for a conversational (non-digit) turn
|
|
2413
2441
|
context_messages = [
|
|
2414
2442
|
{"role": "user", "content": turn}
|
|
2415
2443
|
for turn in turns
|
|
@@ -2422,39 +2450,67 @@ In all of these cases, you can provide a `name` in your new node's config for de
|
|
|
2422
2450
|
llm_service = llm_service.active_llm
|
|
2423
2451
|
schema = build_router_response_schema(
|
|
2424
2452
|
[],
|
|
2425
|
-
{
|
|
2426
|
-
"
|
|
2427
|
-
|
|
2428
|
-
|
|
2453
|
+
{
|
|
2454
|
+
"value": {
|
|
2455
|
+
"type": "string",
|
|
2456
|
+
"description": (
|
|
2457
|
+
f"The {what} as digits 0-9 only, in the order spoken (no spaces or "
|
|
2458
|
+
"punctuation). Join each spoken number-word left to right — e.g. "
|
|
2459
|
+
"'double seven' → '77', 'nine two triple two' → 9,2,222 → '92222', "
|
|
2460
|
+
"'eight one three zero' → '8130'. Return an empty string if the "
|
|
2461
|
+
"caller has not given any digits yet (e.g. only said 'hello') — "
|
|
2462
|
+
"never invent or guess digits."
|
|
2463
|
+
),
|
|
2464
|
+
},
|
|
2465
|
+
"readback": {
|
|
2466
|
+
"type": "string",
|
|
2467
|
+
"description": (
|
|
2468
|
+
"A read-back of `value` for confirmation, in the caller's language, "
|
|
2469
|
+
"with repeated digits grouped — e.g. 8555 → 'eight triple five', "
|
|
2470
|
+
"77 → 'double seven'. Empty when `value` is empty."
|
|
2471
|
+
),
|
|
2472
|
+
},
|
|
2473
|
+
"reply": {
|
|
2474
|
+
"type": "string",
|
|
2475
|
+
"description": (
|
|
2476
|
+
"Empty whenever the caller gave digits. ONLY when they gave no "
|
|
2477
|
+
"digits and instead said something conversational (a question, a "
|
|
2478
|
+
"hesitation, an objection), a SHORT reply in their language that "
|
|
2479
|
+
"answers in ONE sentence and then asks again for the number. Stay "
|
|
2480
|
+
"on topic; for anything unrelated give a one-line redirect back to "
|
|
2481
|
+
"the number; make no promises or commitments."
|
|
2482
|
+
),
|
|
2483
|
+
},
|
|
2484
|
+
},
|
|
2429
2485
|
)
|
|
2430
2486
|
try:
|
|
2431
2487
|
raw = await self._timed_router_completion(
|
|
2432
2488
|
node_id,
|
|
2433
2489
|
llm_service=llm_service,
|
|
2434
2490
|
system_prompt=(
|
|
2435
|
-
f"The caller is
|
|
2436
|
-
"
|
|
2437
|
-
"
|
|
2438
|
-
|
|
2439
|
-
"
|
|
2440
|
-
"
|
|
2441
|
-
"
|
|
2442
|
-
"
|
|
2443
|
-
"
|
|
2444
|
-
"
|
|
2445
|
-
"
|
|
2446
|
-
"
|
|
2447
|
-
"
|
|
2448
|
-
"
|
|
2449
|
-
"
|
|
2450
|
-
"
|
|
2451
|
-
"
|
|
2452
|
-
"
|
|
2453
|
-
"
|
|
2454
|
-
"
|
|
2455
|
-
"'70823 41303' then '
|
|
2456
|
-
"'
|
|
2457
|
-
"
|
|
2491
|
+
f"The caller is giving you a {what} — by voice in ANY language, or by "
|
|
2492
|
+
"keypad (a message like 'User inputted: 5') — possibly across several "
|
|
2493
|
+
"messages. Read everything they have said and return the final number "
|
|
2494
|
+
"in `value` and `readback`, or leave both empty if no digits have been "
|
|
2495
|
+
"given yet.\n"
|
|
2496
|
+
"If the caller instead said something conversational (a question, a "
|
|
2497
|
+
"hesitation, an objection) and gave NO digits, leave value/readback "
|
|
2498
|
+
"empty and put a SHORT on-topic reply in `reply`: answer in one "
|
|
2499
|
+
"sentence, then ask again for the number — stay on topic, make no "
|
|
2500
|
+
"promises.\n"
|
|
2501
|
+
"Digits: read each spoken number-word in the order spoken and join its "
|
|
2502
|
+
"digits left to right — a digit-word adds one digit, 'double X' adds "
|
|
2503
|
+
"XX, 'triple X' adds XXX (in any language, incl. डबल/ट्रिपल), and a lone "
|
|
2504
|
+
"digit next to a double/triple word stays separate.\n"
|
|
2505
|
+
"Corrections: if the caller fixes or restates any part — 'no, the "
|
|
2506
|
+
"first/last part is X', 'the start/beginning is X' (शुरू/स्टार्टिंग), "
|
|
2507
|
+
"'the end is X' (एंड/लास्ट), 'where I said Y it's Z', or they repeat the "
|
|
2508
|
+
"whole number — apply it and output the single final number, keeping "
|
|
2509
|
+
"the un-corrected digits unchanged. When the position is vague, find "
|
|
2510
|
+
"the run of digits being replaced and swap only that run. Examples: "
|
|
2511
|
+
"'70823 41303' then 'no, the first part is 807' → '8072341303'; then "
|
|
2512
|
+
"'एंड में 5 है' → '7082341305'; then 'where I said 41 it's 14' → "
|
|
2513
|
+
"'7082314303'."
|
|
2458
2514
|
),
|
|
2459
2515
|
response_schema=schema,
|
|
2460
2516
|
context_messages=context_messages,
|
|
@@ -2467,6 +2523,10 @@ In all of these cases, you can provide a `name` in your new node's config for de
|
|
|
2467
2523
|
return ""
|
|
2468
2524
|
_branch, extracted = parse_router_response(raw, [UNCLEAR_BRANCH_ID])
|
|
2469
2525
|
value = (extracted or {}).get("value")
|
|
2526
|
+
readback = (extracted or {}).get("readback")
|
|
2527
|
+
reply = (extracted or {}).get("reply")
|
|
2528
|
+
self._collect_readback = readback.strip() if isinstance(readback, str) else ""
|
|
2529
|
+
self._collect_reply = reply.strip() if isinstance(reply, str) else ""
|
|
2470
2530
|
return re.sub(r"\D", "", value) if isinstance(value, str) else ""
|
|
2471
2531
|
|
|
2472
2532
|
async def _reextract_if_corrected(
|
|
@@ -2580,20 +2640,17 @@ In all of these cases, you can provide a `name` in your new node's config for de
|
|
|
2580
2640
|
# ignore the rejected attempt's turns.
|
|
2581
2641
|
start_ts = time.monotonic()
|
|
2582
2642
|
buffer = ""
|
|
2643
|
+
echoed = "" # bare digits already spoken back, so we echo only the NEW ones
|
|
2583
2644
|
misses = 0
|
|
2645
|
+
replies = 0 # conversational (non-digit) replies, bounded so chatter can't loop
|
|
2584
2646
|
corrections = 0 # confirm "no" rounds, bounded so a correction can't loop
|
|
2585
2647
|
deadline = time.monotonic() + self._MAX_CAPTURE_SECONDS
|
|
2586
2648
|
|
|
2587
2649
|
async def _nudge(language: str) -> None:
|
|
2588
|
-
"""Re-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
await self._task.queue_frame(TTSSpeakFrame(text=collect_prompt(
|
|
2593
|
-
language, "continue_partial", readback=" ".join(buffer),
|
|
2594
|
-
remaining=remaining, unit=unit,
|
|
2595
|
-
)))
|
|
2596
|
-
elif reask:
|
|
2650
|
+
"""Re-prompt ONLY when we have nothing yet (the author's reask). Holding a
|
|
2651
|
+
partial → stay silent: the progress echo already spoke the digits, so
|
|
2652
|
+
re-speaking them just sounds like a repeat (and talks over the caller)."""
|
|
2653
|
+
if not buffer and reask:
|
|
2597
2654
|
await self._task.queue_frame(TTSSpeakFrame(text=reask))
|
|
2598
2655
|
|
|
2599
2656
|
while misses < max_attempts:
|
|
@@ -2601,7 +2658,7 @@ In all of these cases, you can provide a `name` in your new node's config for de
|
|
|
2601
2658
|
# Longer window to START dictating; 7s once we hold a partial. Patient
|
|
2602
2659
|
# while the caller is mid-utterance, so a timeout can't clip them.
|
|
2603
2660
|
got_turn = await self._wait_for_caller_input(
|
|
2604
|
-
|
|
2661
|
+
7.0 if buffer else 15.0, deadline, allow_keypad, keypad_dtmf
|
|
2605
2662
|
)
|
|
2606
2663
|
if not got_turn:
|
|
2607
2664
|
if time.monotonic() >= deadline:
|
|
@@ -2635,7 +2692,9 @@ In all of these cases, you can provide a `name` in your new node's config for de
|
|
|
2635
2692
|
# the ORIGINAL number. Only a plain rejection with no new digits
|
|
2636
2693
|
# falls through to the re-ask. Bounded by ``corrections``.
|
|
2637
2694
|
while True:
|
|
2638
|
-
confirmed = await self._confirm_collected(
|
|
2695
|
+
confirmed = await self._confirm_collected(
|
|
2696
|
+
node_id, getattr(self, "_collect_readback", "") or " ".join(buffer)
|
|
2697
|
+
)
|
|
2639
2698
|
if confirmed is True:
|
|
2640
2699
|
return normalized
|
|
2641
2700
|
corrections += 1
|
|
@@ -2661,6 +2720,7 @@ In all of these cases, you can provide a `name` in your new node's config for de
|
|
|
2661
2720
|
# Enough digits but not a valid number → reset and re-ask.
|
|
2662
2721
|
start_ts = time.monotonic()
|
|
2663
2722
|
buffer = ""
|
|
2723
|
+
echoed = ""
|
|
2664
2724
|
misses += 1
|
|
2665
2725
|
if misses < max_attempts:
|
|
2666
2726
|
await self._task.queue_frame(
|
|
@@ -2668,17 +2728,49 @@ In all of these cases, you can provide a `name` in your new node's config for de
|
|
|
2668
2728
|
)
|
|
2669
2729
|
continue
|
|
2670
2730
|
|
|
2671
|
-
if
|
|
2672
|
-
# A turn arrived but
|
|
2673
|
-
#
|
|
2731
|
+
if buffer == previous:
|
|
2732
|
+
# A turn arrived but the number is UNCHANGED (filler / mis-hear / a
|
|
2733
|
+
# request to repeat). If the caller asked to hear it back, RE-READ the
|
|
2734
|
+
# digits-so-far (no miss); otherwise re-ask and count a miss so garbage
|
|
2735
|
+
# can't loop forever. Compare by VALUE, not length: a same-length
|
|
2736
|
+
# correction during the echo phase ("no, the 3rd is 5": 7765 → 7755)
|
|
2737
|
+
# changes the value but not the length, so a length check would mis-read
|
|
2738
|
+
# the fix as "no progress" and burn a miss instead of echoing it below.
|
|
2739
|
+
turns = self._collect_turns_since(start_ts)
|
|
2740
|
+
if buffer and turns and is_repeat_request(turns[-1]):
|
|
2741
|
+
# Re-reads bypass the miss counter, so the absolute deadline is the
|
|
2742
|
+
# only bound — without it a caller repeating "say it again" loops
|
|
2743
|
+
# forever (a turn lands every cycle, never silence, never a miss).
|
|
2744
|
+
if time.monotonic() >= deadline:
|
|
2745
|
+
break
|
|
2746
|
+
await self._task.queue_frame(TTSSpeakFrame(
|
|
2747
|
+
text=collect_prompt(language, "echo", digits=" ".join(buffer))
|
|
2748
|
+
))
|
|
2749
|
+
continue
|
|
2750
|
+
reply = getattr(self, "_collect_reply", "")
|
|
2751
|
+
if reply and replies < self._MAX_COLLECT_REPLIES and time.monotonic() < deadline:
|
|
2752
|
+
# The caller said something other than digits (a question / objection).
|
|
2753
|
+
# Speak the LLM's on-topic reply (it answers AND steers back to the
|
|
2754
|
+
# number) instead of the robotic nudge. Bounded + deadline-capped so it
|
|
2755
|
+
# can't crowd out give-up; a repeat request was already handled above.
|
|
2756
|
+
replies += 1
|
|
2757
|
+
await self._task.queue_frame(TTSSpeakFrame(text=reply))
|
|
2758
|
+
continue
|
|
2674
2759
|
misses += 1
|
|
2675
2760
|
if misses < max_attempts:
|
|
2676
2761
|
await _nudge(language)
|
|
2677
2762
|
continue
|
|
2678
2763
|
|
|
2679
|
-
# Buffer
|
|
2680
|
-
#
|
|
2681
|
-
#
|
|
2764
|
+
# Buffer CHANGED (progress — new digits OR a correction) → echo it back
|
|
2765
|
+
# (bare, in the caller's language) so they hear we caught the change, and
|
|
2766
|
+
# reset the give-up counter. A clean append echoes only the NEW digits; a
|
|
2767
|
+
# correction (not a prefix of what we echoed) re-echoes the full number.
|
|
2768
|
+
delta = buffer[len(echoed):] if buffer.startswith(echoed) else buffer
|
|
2769
|
+
if delta:
|
|
2770
|
+
await self._task.queue_frame(TTSSpeakFrame(
|
|
2771
|
+
text=collect_prompt(language, "echo", digits=" ".join(delta))
|
|
2772
|
+
))
|
|
2773
|
+
echoed = buffer
|
|
2682
2774
|
misses = 0
|
|
2683
2775
|
|
|
2684
2776
|
logger.info(f"Collect '{node_id}': gave up after {misses} misses (buffer='{buffer}')")
|
|
@@ -2707,27 +2799,24 @@ In all of these cases, you can provide a `name` in your new node's config for de
|
|
|
2707
2799
|
target = int(num_digits) if num_digits else 6
|
|
2708
2800
|
start_ts = time.monotonic()
|
|
2709
2801
|
buffer = ""
|
|
2802
|
+
echoed = "" # bare digits already spoken back, so we echo only the NEW ones
|
|
2710
2803
|
misses = 0
|
|
2804
|
+
replies = 0 # conversational (non-digit) replies, bounded so chatter can't loop
|
|
2711
2805
|
corrections = 0 # confirm "no" rounds, bounded so a correction can't loop
|
|
2712
2806
|
deadline = time.monotonic() + self._MAX_CAPTURE_SECONDS
|
|
2713
2807
|
# Keypad auto-flushes once the caller has keyed `target` digits.
|
|
2714
2808
|
code_dtmf = {**(keypad_dtmf or {}), "digits": target}
|
|
2715
2809
|
|
|
2716
2810
|
async def _nudge(language: str) -> None:
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
await self._task.queue_frame(TTSSpeakFrame(text=collect_prompt(
|
|
2721
|
-
language, "continue_partial", readback=" ".join(buffer),
|
|
2722
|
-
remaining=remaining, unit=unit,
|
|
2723
|
-
)))
|
|
2724
|
-
elif reask:
|
|
2811
|
+
"""Re-prompt ONLY when we have nothing yet (the author's reask); holding a
|
|
2812
|
+
partial → stay silent (the progress echo already spoke the digits)."""
|
|
2813
|
+
if not buffer and reask:
|
|
2725
2814
|
await self._task.queue_frame(TTSSpeakFrame(text=reask))
|
|
2726
2815
|
|
|
2727
2816
|
while misses < max_attempts:
|
|
2728
2817
|
language = self._active_language()
|
|
2729
2818
|
got_turn = await self._wait_for_caller_input(
|
|
2730
|
-
|
|
2819
|
+
7.0 if buffer else 15.0, deadline, allow_keypad, code_dtmf
|
|
2731
2820
|
)
|
|
2732
2821
|
if not got_turn:
|
|
2733
2822
|
if time.monotonic() >= deadline:
|
|
@@ -2754,7 +2843,9 @@ In all of these cases, you can provide a `name` in your new node's config for de
|
|
|
2754
2843
|
# we already have and re-reads the CORRECTED code at once; only a
|
|
2755
2844
|
# plain rejection with no new digits asks "what should it be?".
|
|
2756
2845
|
while True:
|
|
2757
|
-
confirmed = await self._confirm_collected(
|
|
2846
|
+
confirmed = await self._confirm_collected(
|
|
2847
|
+
node_id, getattr(self, "_collect_readback", "") or " ".join(normalized)
|
|
2848
|
+
)
|
|
2758
2849
|
if confirmed is True:
|
|
2759
2850
|
return normalized
|
|
2760
2851
|
corrections += 1
|
|
@@ -2780,6 +2871,7 @@ In all of these cases, you can provide a `name` in your new node's config for de
|
|
|
2780
2871
|
# Too many digits for this code → reset and re-ask.
|
|
2781
2872
|
start_ts = time.monotonic()
|
|
2782
2873
|
buffer = ""
|
|
2874
|
+
echoed = ""
|
|
2783
2875
|
misses += 1
|
|
2784
2876
|
if misses < max_attempts:
|
|
2785
2877
|
await self._task.queue_frame(
|
|
@@ -2787,14 +2879,45 @@ In all of these cases, you can provide a `name` in your new node's config for de
|
|
|
2787
2879
|
)
|
|
2788
2880
|
continue
|
|
2789
2881
|
|
|
2790
|
-
if
|
|
2791
|
-
#
|
|
2882
|
+
if buffer == previous:
|
|
2883
|
+
# Unchanged (filler / mis-hear / a request to repeat). If the caller
|
|
2884
|
+
# asked to hear it back, RE-READ the digits-so-far (no miss); else re-ask
|
|
2885
|
+
# and count a miss. Compare by VALUE not length so a same-length
|
|
2886
|
+
# correction during the echo phase counts as progress (echoed below).
|
|
2887
|
+
turns = self._collect_turns_since(start_ts)
|
|
2888
|
+
if buffer and turns and is_repeat_request(turns[-1]):
|
|
2889
|
+
# Re-reads bypass the miss counter, so the absolute deadline is the
|
|
2890
|
+
# only bound — without it a caller repeating "say it again" loops
|
|
2891
|
+
# forever (a turn lands every cycle, never silence, never a miss).
|
|
2892
|
+
if time.monotonic() >= deadline:
|
|
2893
|
+
break
|
|
2894
|
+
await self._task.queue_frame(TTSSpeakFrame(
|
|
2895
|
+
text=collect_prompt(language, "echo", digits=" ".join(buffer))
|
|
2896
|
+
))
|
|
2897
|
+
continue
|
|
2898
|
+
reply = getattr(self, "_collect_reply", "")
|
|
2899
|
+
if reply and replies < self._MAX_COLLECT_REPLIES and time.monotonic() < deadline:
|
|
2900
|
+
# The caller said something other than digits (a question / objection).
|
|
2901
|
+
# Speak the LLM's on-topic reply (it answers AND steers back to the
|
|
2902
|
+
# number) instead of the robotic nudge. Bounded + deadline-capped so it
|
|
2903
|
+
# can't crowd out give-up; a repeat request was already handled above.
|
|
2904
|
+
replies += 1
|
|
2905
|
+
await self._task.queue_frame(TTSSpeakFrame(text=reply))
|
|
2906
|
+
continue
|
|
2792
2907
|
misses += 1
|
|
2793
2908
|
if misses < max_attempts:
|
|
2794
2909
|
await _nudge(language)
|
|
2795
2910
|
continue
|
|
2796
2911
|
|
|
2797
|
-
# Buffer
|
|
2912
|
+
# Buffer CHANGED (new digits OR a correction) → echo it back, bare, and
|
|
2913
|
+
# reset the give-up counter. Append → only the new digits; a correction →
|
|
2914
|
+
# the full code re-echoed.
|
|
2915
|
+
delta = buffer[len(echoed):] if buffer.startswith(echoed) else buffer
|
|
2916
|
+
if delta:
|
|
2917
|
+
await self._task.queue_frame(TTSSpeakFrame(
|
|
2918
|
+
text=collect_prompt(language, "echo", digits=" ".join(delta))
|
|
2919
|
+
))
|
|
2920
|
+
echoed = buffer
|
|
2798
2921
|
misses = 0
|
|
2799
2922
|
|
|
2800
2923
|
logger.info(f"Collect '{node_id}': code give-up after {misses} misses (buffer='{buffer}')")
|
|
@@ -2810,7 +2933,9 @@ In all of these cases, you can provide a `name` in your new node's config for de
|
|
|
2810
2933
|
reply ("जी" … "हाँ, सही है") can read as unclear, and we'd rather re-ask
|
|
2811
2934
|
"is that correct?" than treat a confirming caller as a rejection."""
|
|
2812
2935
|
observer = self._user_turn_observer
|
|
2813
|
-
|
|
2936
|
+
repeats = 0
|
|
2937
|
+
asked = 0
|
|
2938
|
+
while asked < max(1, attempts):
|
|
2814
2939
|
listen_ts = time.monotonic()
|
|
2815
2940
|
await self._task.queue_frame(
|
|
2816
2941
|
TTSSpeakFrame(text=collect_prompt(self._active_language(), "confirm", readback=readback))
|
|
@@ -2847,7 +2972,16 @@ In all of these cases, you can provide a `name` in your new node's config for de
|
|
|
2847
2972
|
if observer is not None and hasattr(observer, "transcripts_since")
|
|
2848
2973
|
else ""
|
|
2849
2974
|
)
|
|
2850
|
-
|
|
2975
|
+
has_digit = any(ch.isdigit() for ch in reply)
|
|
2976
|
+
# A request to hear it again ("can you repeat?") is NOT a yes or a no —
|
|
2977
|
+
# re-read the value and DON'T burn a confirm attempt (bounded so a caller
|
|
2978
|
+
# stuck on "repeat" can't loop forever). A digit-carrying reply is a
|
|
2979
|
+
# correction, handled just below, so only a digit-free reply is a repeat.
|
|
2980
|
+
if not has_digit and is_repeat_request(reply):
|
|
2981
|
+
repeats += 1
|
|
2982
|
+
if repeats <= 3:
|
|
2983
|
+
continue
|
|
2984
|
+
if has_digit:
|
|
2851
2985
|
return False
|
|
2852
2986
|
text = (answer or "").strip().lower()
|
|
2853
2987
|
if text.startswith("yes"):
|
|
@@ -2855,6 +2989,7 @@ In all of these cases, you can provide a `name` in your new node's config for de
|
|
|
2855
2989
|
if text.startswith("no"):
|
|
2856
2990
|
return False
|
|
2857
2991
|
# null / unclear → re-ask "is that correct?" (next loop iteration)
|
|
2992
|
+
asked += 1
|
|
2858
2993
|
return None
|
|
2859
2994
|
|
|
2860
2995
|
async def _collect_single_value(
|
|
@@ -2874,9 +3009,11 @@ In all of these cases, you can provide a `name` in your new node's config for de
|
|
|
2874
3009
|
description = {
|
|
2875
3010
|
"email": "the email address the caller said, as a standard address (e.g. john.smith@gmail.com)",
|
|
2876
3011
|
}.get(collect_type, "the value the caller said")
|
|
2877
|
-
|
|
3012
|
+
attempt = 0
|
|
3013
|
+
replies = 0
|
|
3014
|
+
while attempt < max_attempts:
|
|
2878
3015
|
raw_value = await self._extract_spoken_value(
|
|
2879
|
-
node_id, description, timeout_s=15.0
|
|
3016
|
+
node_id, description, timeout_s=15.0, with_reply=True
|
|
2880
3017
|
)
|
|
2881
3018
|
if not raw_value and allow_keypad:
|
|
2882
3019
|
capture_timeout = float(keypad_dtmf.get("timeout", 8.0)) + 10.0
|
|
@@ -2886,27 +3023,53 @@ In all of these cases, you can provide a `name` in your new node's config for de
|
|
|
2886
3023
|
if raw_value and self._caller_is_speaking():
|
|
2887
3024
|
if await self._await_user_turn(timeout_s=5.0):
|
|
2888
3025
|
raw_value = await self._extract_spoken_value(
|
|
2889
|
-
node_id, description, timeout_s=15.0
|
|
3026
|
+
node_id, description, timeout_s=15.0, with_reply=True
|
|
2890
3027
|
)
|
|
2891
3028
|
normalized = normalize_collect_value(
|
|
2892
3029
|
collect_type, raw_value, country_default=country_default
|
|
2893
3030
|
)
|
|
2894
3031
|
if normalized:
|
|
2895
|
-
# Read the value back and confirm before storing (phone-parity).
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
#
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
3032
|
+
# Read the value back and confirm before storing (phone-parity). On a
|
|
3033
|
+
# denial, re-extract from the rejection reply itself ("no, it's
|
|
3034
|
+
# jane@gmail.com") and re-confirm the fix directly, instead of making
|
|
3035
|
+
# the caller repeat the whole address. A plain "no" with no new value
|
|
3036
|
+
# falls through to "what should it be?" and the next attempt.
|
|
3037
|
+
while True:
|
|
3038
|
+
confirm_ts = time.monotonic()
|
|
3039
|
+
confirmed = await self._confirm_collected(node_id, normalized)
|
|
3040
|
+
if confirmed is True:
|
|
3041
|
+
return normalized
|
|
3042
|
+
corrected = normalize_collect_value(
|
|
3043
|
+
collect_type,
|
|
3044
|
+
await self._extract_spoken_value(
|
|
3045
|
+
node_id, description, timeout_s=0.0, since_ts=confirm_ts
|
|
3046
|
+
),
|
|
3047
|
+
country_default=country_default,
|
|
2903
3048
|
)
|
|
3049
|
+
if corrected and corrected != normalized:
|
|
3050
|
+
normalized = corrected
|
|
3051
|
+
continue # re-read the corrected value for confirmation
|
|
3052
|
+
if attempt < max_attempts - 1:
|
|
3053
|
+
await self._task.queue_frame(
|
|
3054
|
+
TTSSpeakFrame(text=collect_prompt(self._active_language(), "restart_denied"))
|
|
3055
|
+
)
|
|
3056
|
+
break
|
|
3057
|
+
attempt += 1
|
|
3058
|
+
continue
|
|
3059
|
+
# No valid value. If the caller said something conversational instead, speak
|
|
3060
|
+
# the LLM's on-topic reply (it answers AND steers back) WITHOUT burning an
|
|
3061
|
+
# attempt (bounded). Otherwise count the attempt and re-ask.
|
|
3062
|
+
reply = getattr(self, "_collect_reply", "")
|
|
3063
|
+
if reply and replies < self._MAX_COLLECT_REPLIES:
|
|
3064
|
+
replies += 1
|
|
3065
|
+
await self._task.queue_frame(TTSSpeakFrame(text=reply))
|
|
2904
3066
|
continue
|
|
3067
|
+
attempt += 1
|
|
2905
3068
|
logger.info(
|
|
2906
3069
|
f"Collect '{node_id}': no valid {collect_type} "
|
|
2907
|
-
f"(attempt {attempt
|
|
3070
|
+
f"(attempt {attempt}/{max_attempts})"
|
|
2908
3071
|
)
|
|
2909
|
-
if reask and attempt < max_attempts
|
|
3072
|
+
if reask and attempt < max_attempts:
|
|
2910
3073
|
await self._task.queue_frame(TTSSpeakFrame(text=reask))
|
|
2911
3074
|
return None
|
|
2912
3075
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/editor/js/editor/canvas.js
RENAMED
|
File without changes
|
{dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/editor/js/editor/editorState.js
RENAMED
|
File without changes
|
{dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/editor/js/editor/sidePanel.js
RENAMED
|
File without changes
|
{dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/editor/js/editor/toolbar.js
RENAMED
|
File without changes
|
|
File without changes
|
{dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/editor/js/nodes/baseNode.js
RENAMED
|
File without changes
|
{dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/editor/js/nodes/endNode.js
RENAMED
|
File without changes
|
{dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/editor/js/nodes/flowNode.js
RENAMED
|
File without changes
|
{dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/editor/js/nodes/functionNode.js
RENAMED
|
File without changes
|
{dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/editor/js/nodes/index.js
RENAMED
|
File without changes
|
{dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/editor/js/nodes/mergeNode.js
RENAMED
|
File without changes
|
{dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/editor/js/nodes/startNode.js
RENAMED
|
File without changes
|
|
File without changes
|
{dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/editor/js/utils/export.js
RENAMED
|
File without changes
|
{dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/editor/js/utils/helpers.js
RENAMED
|
File without changes
|
{dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/editor/js/utils/import.js
RENAMED
|
File without changes
|
{dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/editor/js/utils/validation.js
RENAMED
|
File without changes
|
|
File without changes
|
{dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/editor/package-lock.json
RENAMED
|
File without changes
|
|
File without changes
|
{dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/editor/postcss.config.cjs
RENAMED
|
File without changes
|
{dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/editor/public/favicon.png
RENAMED
|
File without changes
|
{dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/editor/public/favicon.svg
RENAMED
|
File without changes
|
{dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/editor/tailwind.config.cjs
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/engine_primitives_plan.md
RENAMED
|
File without changes
|
|
File without changes
|
{dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/images/food-ordering-flow.png
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/remote-asterisk-code/README.md
RENAMED
|
File without changes
|
|
File without changes
|
{dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/remote-asterisk-code/rtp.conf
RENAMED
|
File without changes
|
|
File without changes
|
{dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/scripts/check-pypi-package.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/src/pipecat_flows/__init__.py
RENAMED
|
File without changes
|
{dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/src/pipecat_flows/actions.py
RENAMED
|
File without changes
|
{dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/src/pipecat_flows/adapters.py
RENAMED
|
File without changes
|
|
File without changes
|
{dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/src/pipecat_flows/exceptions.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/src/pipecat_flows/router_mode.py
RENAMED
|
File without changes
|
{dv_pipecat_flows-0.0.22.dev1487 → dv_pipecat_flows-0.0.22.dev1491}/src/pipecat_flows/types.py
RENAMED
|
File without changes
|
|
File without changes
|