pipecatcloud 0.5.0__tar.gz → 0.6.0__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.
- pipecatcloud-0.6.0/.claude/settings.json +5 -0
- pipecatcloud-0.6.0/.pre-commit-config.yaml +13 -0
- {pipecatcloud-0.5.0 → pipecatcloud-0.6.0}/CHANGELOG.md +25 -0
- {pipecatcloud-0.5.0 → pipecatcloud-0.6.0}/PKG-INFO +1 -1
- {pipecatcloud-0.5.0 → pipecatcloud-0.6.0}/pyproject.toml +13 -0
- {pipecatcloud-0.5.0 → pipecatcloud-0.6.0}/src/pipecatcloud/_utils/auth_utils.py +1 -2
- {pipecatcloud-0.5.0 → pipecatcloud-0.6.0}/src/pipecatcloud/_utils/build_utils.py +40 -14
- {pipecatcloud-0.5.0 → pipecatcloud-0.6.0}/src/pipecatcloud/_utils/console_utils.py +8 -9
- {pipecatcloud-0.5.0 → pipecatcloud-0.6.0}/src/pipecatcloud/_utils/deploy_utils.py +37 -28
- {pipecatcloud-0.5.0 → pipecatcloud-0.6.0}/src/pipecatcloud/_utils/regions.py +3 -5
- {pipecatcloud-0.5.0 → pipecatcloud-0.6.0}/src/pipecatcloud/agent.py +4 -4
- {pipecatcloud-0.5.0 → pipecatcloud-0.6.0}/src/pipecatcloud/api.py +43 -29
- {pipecatcloud-0.5.0 → pipecatcloud-0.6.0}/src/pipecatcloud/cli/commands/agent.py +20 -5
- {pipecatcloud-0.5.0 → pipecatcloud-0.6.0}/src/pipecatcloud/cli/commands/auth.py +10 -10
- {pipecatcloud-0.5.0 → pipecatcloud-0.6.0}/src/pipecatcloud/cli/commands/build.py +6 -8
- {pipecatcloud-0.5.0 → pipecatcloud-0.6.0}/src/pipecatcloud/cli/commands/deploy.py +29 -8
- {pipecatcloud-0.5.0 → pipecatcloud-0.6.0}/src/pipecatcloud/cli/commands/docker.py +2 -3
- {pipecatcloud-0.5.0 → pipecatcloud-0.6.0}/src/pipecatcloud/cli/commands/organizations.py +60 -17
- {pipecatcloud-0.5.0 → pipecatcloud-0.6.0}/src/pipecatcloud/cli/commands/secrets.py +5 -7
- {pipecatcloud-0.5.0 → pipecatcloud-0.6.0}/src/pipecatcloud/cli/config.py +7 -8
- {pipecatcloud-0.5.0 → pipecatcloud-0.6.0}/src/pipecatcloud/exception.py +2 -3
- {pipecatcloud-0.5.0 → pipecatcloud-0.6.0}/src/pipecatcloud/session.py +5 -5
- {pipecatcloud-0.5.0 → pipecatcloud-0.6.0}/src/pipecatcloud/smallwebrtc/session_manager.py +2 -3
- {pipecatcloud-0.5.0 → pipecatcloud-0.6.0}/src/pipecatcloud.egg-info/PKG-INFO +1 -1
- {pipecatcloud-0.5.0 → pipecatcloud-0.6.0}/src/pipecatcloud.egg-info/SOURCES.txt +3 -1
- {pipecatcloud-0.5.0 → pipecatcloud-0.6.0}/tests/test_api_client.py +4 -5
- {pipecatcloud-0.5.0 → pipecatcloud-0.6.0}/tests/test_auth.py +3 -5
- pipecatcloud-0.6.0/tests/test_build_utils.py +151 -0
- {pipecatcloud-0.5.0 → pipecatcloud-0.6.0}/tests/test_deployment_status.py +10 -8
- {pipecatcloud-0.5.0 → pipecatcloud-0.6.0}/tests/test_krisp_viva.py +3 -4
- pipecatcloud-0.6.0/tests/test_max_session_duration.py +154 -0
- {pipecatcloud-0.5.0 → pipecatcloud-0.6.0}/tests/test_pat_auth.py +3 -4
- {pipecatcloud-0.5.0 → pipecatcloud-0.6.0}/uv.lock +3 -3
- pipecatcloud-0.5.0/.pre-commit-config.yaml +0 -8
- pipecatcloud-0.5.0/scripts/pre-commit.sh +0 -27
- {pipecatcloud-0.5.0 → pipecatcloud-0.6.0}/.github/workflows/format.yml +0 -0
- {pipecatcloud-0.5.0 → pipecatcloud-0.6.0}/.github/workflows/publish-pypi.yml +0 -0
- {pipecatcloud-0.5.0 → pipecatcloud-0.6.0}/.github/workflows/publish-test.yml +0 -0
- {pipecatcloud-0.5.0 → pipecatcloud-0.6.0}/.github/workflows/tests.yml +0 -0
- {pipecatcloud-0.5.0 → pipecatcloud-0.6.0}/.gitignore +0 -0
- {pipecatcloud-0.5.0 → pipecatcloud-0.6.0}/LICENSE +0 -0
- {pipecatcloud-0.5.0 → pipecatcloud-0.6.0}/README.md +0 -0
- {pipecatcloud-0.5.0 → pipecatcloud-0.6.0}/pipecat-cloud.png +0 -0
- {pipecatcloud-0.5.0 → pipecatcloud-0.6.0}/pytest.ini +0 -0
- {pipecatcloud-0.5.0 → pipecatcloud-0.6.0}/scripts/fix-ruff.sh +0 -0
- {pipecatcloud-0.5.0 → pipecatcloud-0.6.0}/setup.cfg +0 -0
- {pipecatcloud-0.5.0 → pipecatcloud-0.6.0}/src/pipecatcloud/__init__.py +0 -0
- {pipecatcloud-0.5.0 → pipecatcloud-0.6.0}/src/pipecatcloud/__main__.py +0 -0
- {pipecatcloud-0.5.0 → pipecatcloud-0.6.0}/src/pipecatcloud/__version__.py +0 -0
- {pipecatcloud-0.5.0 → pipecatcloud-0.6.0}/src/pipecatcloud/_utils/__init__.py +0 -0
- {pipecatcloud-0.5.0 → pipecatcloud-0.6.0}/src/pipecatcloud/_utils/async_utils.py +0 -0
- {pipecatcloud-0.5.0 → pipecatcloud-0.6.0}/src/pipecatcloud/cli/__init__.py +0 -0
- {pipecatcloud-0.5.0 → pipecatcloud-0.6.0}/src/pipecatcloud/cli/api.py +0 -0
- {pipecatcloud-0.5.0 → pipecatcloud-0.6.0}/src/pipecatcloud/cli/commands/__init__.py +0 -0
- {pipecatcloud-0.5.0 → pipecatcloud-0.6.0}/src/pipecatcloud/cli/commands/regions.py +0 -0
- {pipecatcloud-0.5.0 → pipecatcloud-0.6.0}/src/pipecatcloud/cli/entry_point.py +0 -0
- {pipecatcloud-0.5.0 → pipecatcloud-0.6.0}/src/pipecatcloud/config.py +0 -0
- {pipecatcloud-0.5.0 → pipecatcloud-0.6.0}/src/pipecatcloud/constants.py +0 -0
- {pipecatcloud-0.5.0 → pipecatcloud-0.6.0}/src/pipecatcloud/py.typed +0 -0
- {pipecatcloud-0.5.0 → pipecatcloud-0.6.0}/src/pipecatcloud.egg-info/dependency_links.txt +0 -0
- {pipecatcloud-0.5.0 → pipecatcloud-0.6.0}/src/pipecatcloud.egg-info/entry_points.txt +0 -0
- {pipecatcloud-0.5.0 → pipecatcloud-0.6.0}/src/pipecatcloud.egg-info/requires.txt +0 -0
- {pipecatcloud-0.5.0 → pipecatcloud-0.6.0}/src/pipecatcloud.egg-info/top_level.txt +0 -0
- {pipecatcloud-0.5.0 → pipecatcloud-0.6.0}/tests/__init__.py +0 -0
- {pipecatcloud-0.5.0 → pipecatcloud-0.6.0}/tests/conftest.py +0 -0
- {pipecatcloud-0.5.0 → pipecatcloud-0.6.0}/tests/test_agent_sessions.py +0 -0
- {pipecatcloud-0.5.0 → pipecatcloud-0.6.0}/tests/test_agent_stop.py +0 -0
- {pipecatcloud-0.5.0 → pipecatcloud-0.6.0}/tests/test_config_file.py +0 -0
- {pipecatcloud-0.5.0 → pipecatcloud-0.6.0}/tests/test_docker_commands.py +0 -0
- {pipecatcloud-0.5.0 → pipecatcloud-0.6.0}/tests/test_regions.py +0 -0
|
@@ -5,6 +5,31 @@ All notable changes to **Pipecat Cloud** will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.6.0] - 2026-04-22
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- `websocket_auth` config option in `pcc-deploy.toml` to control authentication
|
|
13
|
+
mode for the generic WebSocket handler (`/ws/generic`). Valid values are
|
|
14
|
+
`"none"` (no authentication required) and `"token"` (requires a session token
|
|
15
|
+
obtained via `/start`). New services default to `"token"` if not specified.
|
|
16
|
+
|
|
17
|
+
- `--max-session-duration` flag on `pcc deploy` for configuring the
|
|
18
|
+
per-service maximum session duration in seconds. Accepts values
|
|
19
|
+
between 60 and 14400 (4 hours), defaulting to 7200 (2 hours) when
|
|
20
|
+
unset. Also exposed in `pcc agent status` output and as
|
|
21
|
+
`max_session_duration` in `pcc-deploy.toml`.
|
|
22
|
+
|
|
23
|
+
### Fixed
|
|
24
|
+
|
|
25
|
+
- `.dockerignore` patterns written with Docker's conventional trailing
|
|
26
|
+
slash (e.g. `.venv/`, `node_modules/`) and leading `./` anchors
|
|
27
|
+
(e.g. `./dist`) now match correctly in cloud builds. Previously the
|
|
28
|
+
CLI compared patterns with `fnmatch`, which treats both forms as
|
|
29
|
+
literal text, so these entries silently excluded nothing and large
|
|
30
|
+
directories like `.venv/` could leak into the build context and
|
|
31
|
+
trip the 500 MB limit.
|
|
32
|
+
|
|
8
33
|
## [0.5.0] - 2026-04-17
|
|
9
34
|
|
|
10
35
|
### Changed
|
|
@@ -59,6 +59,19 @@ pipecatcloud = ["py.typed"]
|
|
|
59
59
|
exclude = ["*_pb2.py"]
|
|
60
60
|
line-length = 100
|
|
61
61
|
|
|
62
|
+
[tool.ruff.lint]
|
|
63
|
+
select = [
|
|
64
|
+
"I", # Import rules
|
|
65
|
+
"UP", # Modern Python
|
|
66
|
+
]
|
|
67
|
+
|
|
68
|
+
[tool.ruff.lint.per-file-ignores]
|
|
69
|
+
# Skip docstring checks for non-source code
|
|
70
|
+
"tests/**/*.py" = ["D"]
|
|
71
|
+
"scripts/**/*.py" = ["D"]
|
|
72
|
+
# Skip D104 (missing docstring in public package) for __init__.py files
|
|
73
|
+
"**/__init__.py" = ["D104"]
|
|
74
|
+
|
|
62
75
|
[project.urls]
|
|
63
76
|
Website = "https://docs.pipecat.daily.co/"
|
|
64
77
|
|
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
#
|
|
6
6
|
|
|
7
7
|
import functools
|
|
8
|
-
from typing import Optional
|
|
9
8
|
|
|
10
9
|
import aiohttp
|
|
11
10
|
|
|
@@ -15,7 +14,7 @@ from pipecatcloud.cli import PIPECAT_CLI_NAME
|
|
|
15
14
|
from pipecatcloud.cli.config import config
|
|
16
15
|
|
|
17
16
|
|
|
18
|
-
async def _resolve_default_org(token: str) ->
|
|
17
|
+
async def _resolve_default_org(token: str) -> str | None:
|
|
19
18
|
"""Fetch the user's default organization using the given token."""
|
|
20
19
|
from pipecatcloud.config import config as base_config
|
|
21
20
|
|
|
@@ -19,15 +19,15 @@ import io
|
|
|
19
19
|
import os
|
|
20
20
|
import tarfile
|
|
21
21
|
import time
|
|
22
|
+
from collections.abc import Callable
|
|
22
23
|
from dataclasses import dataclass
|
|
23
24
|
from pathlib import Path
|
|
24
|
-
from typing import Callable, List, Optional, Set, Tuple
|
|
25
25
|
|
|
26
26
|
import aiohttp
|
|
27
27
|
from loguru import logger
|
|
28
28
|
|
|
29
29
|
# Default patterns to exclude from build context
|
|
30
|
-
DEFAULT_EXCLUSIONS:
|
|
30
|
+
DEFAULT_EXCLUSIONS: set[str] = {
|
|
31
31
|
# Version control
|
|
32
32
|
".git",
|
|
33
33
|
".gitignore",
|
|
@@ -116,7 +116,7 @@ class BuildStatus:
|
|
|
116
116
|
return status in cls.TERMINAL_STATUSES
|
|
117
117
|
|
|
118
118
|
|
|
119
|
-
def _should_exclude(path: Path, exclusions:
|
|
119
|
+
def _should_exclude(path: Path, exclusions: set[str], base_path: Path) -> bool:
|
|
120
120
|
"""
|
|
121
121
|
Check if a path should be excluded from the build context.
|
|
122
122
|
|
|
@@ -143,7 +143,27 @@ def _should_exclude(path: Path, exclusions: Set[str], base_path: Path) -> bool:
|
|
|
143
143
|
return False
|
|
144
144
|
|
|
145
145
|
|
|
146
|
-
def
|
|
146
|
+
def _normalize_pattern(pattern: str) -> str:
|
|
147
|
+
"""Normalize a single ``.dockerignore`` pattern for ``fnmatch`` matching.
|
|
148
|
+
|
|
149
|
+
The matcher in ``_should_exclude`` walks the tree and compares each
|
|
150
|
+
path component against every pattern with ``fnmatch.fnmatch``, which
|
|
151
|
+
treats the pattern as literal text. ``.dockerignore`` (and the
|
|
152
|
+
companion ``.gitignore`` grammar users pattern after) allows a few
|
|
153
|
+
pieces of sugar that ``fnmatch`` does not understand: a trailing
|
|
154
|
+
slash meaning "directory only", and a leading ``./`` anchoring to
|
|
155
|
+
the context root. Both forms are common in the wild and routinely
|
|
156
|
+
silently match nothing under a raw ``fnmatch`` implementation, so
|
|
157
|
+
we strip them here to make the pattern intent actually take effect.
|
|
158
|
+
"""
|
|
159
|
+
normalized = pattern.strip()
|
|
160
|
+
if normalized.startswith("./"):
|
|
161
|
+
normalized = normalized[2:]
|
|
162
|
+
normalized = normalized.rstrip("/")
|
|
163
|
+
return normalized
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def load_dockerignore(context_dir: Path) -> set[str] | None:
|
|
147
167
|
"""
|
|
148
168
|
Load patterns from .dockerignore file if it exists.
|
|
149
169
|
|
|
@@ -159,12 +179,15 @@ def load_dockerignore(context_dir: Path) -> Optional[Set[str]]:
|
|
|
159
179
|
|
|
160
180
|
patterns = set()
|
|
161
181
|
try:
|
|
162
|
-
with open(dockerignore_path
|
|
182
|
+
with open(dockerignore_path) as f:
|
|
163
183
|
for line in f:
|
|
164
|
-
|
|
184
|
+
stripped = line.strip()
|
|
165
185
|
# Skip comments and empty lines
|
|
166
|
-
if
|
|
167
|
-
|
|
186
|
+
if not stripped or stripped.startswith("#"):
|
|
187
|
+
continue
|
|
188
|
+
normalized = _normalize_pattern(stripped)
|
|
189
|
+
if normalized:
|
|
190
|
+
patterns.add(normalized)
|
|
168
191
|
except Exception as e:
|
|
169
192
|
logger.warning(f"Failed to read .dockerignore: {e}")
|
|
170
193
|
return None
|
|
@@ -172,7 +195,7 @@ def load_dockerignore(context_dir: Path) -> Optional[Set[str]]:
|
|
|
172
195
|
return patterns
|
|
173
196
|
|
|
174
197
|
|
|
175
|
-
def get_exclusions(context_dir: Path, extra_patterns:
|
|
198
|
+
def get_exclusions(context_dir: Path, extra_patterns: list[str] | None = None) -> set[str]:
|
|
176
199
|
"""
|
|
177
200
|
Get the set of exclusion patterns to use.
|
|
178
201
|
|
|
@@ -195,13 +218,16 @@ def get_exclusions(context_dir: Path, extra_patterns: Optional[List[str]] = None
|
|
|
195
218
|
# Use defaults + extras
|
|
196
219
|
exclusions = DEFAULT_EXCLUSIONS.copy()
|
|
197
220
|
if extra_patterns:
|
|
198
|
-
|
|
221
|
+
for extra in extra_patterns:
|
|
222
|
+
normalized = _normalize_pattern(extra)
|
|
223
|
+
if normalized:
|
|
224
|
+
exclusions.add(normalized)
|
|
199
225
|
return exclusions
|
|
200
226
|
|
|
201
227
|
|
|
202
228
|
def create_deterministic_tarball(
|
|
203
229
|
context_dir: str,
|
|
204
|
-
exclusions:
|
|
230
|
+
exclusions: set[str],
|
|
205
231
|
dockerfile_path: str = "Dockerfile",
|
|
206
232
|
) -> BuildContext:
|
|
207
233
|
"""
|
|
@@ -235,7 +261,7 @@ def create_deterministic_tarball(
|
|
|
235
261
|
raise FileNotFoundError(f"Dockerfile not found: {dockerfile_full}")
|
|
236
262
|
|
|
237
263
|
# Collect all files, sorted alphabetically
|
|
238
|
-
files_to_add:
|
|
264
|
+
files_to_add: list[tuple[Path, str]] = []
|
|
239
265
|
|
|
240
266
|
for root, dirs, files in os.walk(base_path):
|
|
241
267
|
root_path = Path(root)
|
|
@@ -363,8 +389,8 @@ async def poll_build_status(
|
|
|
363
389
|
api_client,
|
|
364
390
|
poll_interval: float = 3.0,
|
|
365
391
|
max_duration: float = 600.0, # 10 minutes
|
|
366
|
-
status_callback:
|
|
367
|
-
) ->
|
|
392
|
+
status_callback: Callable[[dict], None] | None = None,
|
|
393
|
+
) -> tuple[bool, dict]:
|
|
368
394
|
"""
|
|
369
395
|
Poll build status until completion or timeout.
|
|
370
396
|
|
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
|
|
7
7
|
import statistics
|
|
8
8
|
from datetime import datetime
|
|
9
|
-
from typing import Optional, Union
|
|
10
9
|
|
|
11
10
|
from rich.console import Console
|
|
12
11
|
from rich.panel import Panel
|
|
@@ -18,9 +17,9 @@ class PipecatConsole(Console):
|
|
|
18
17
|
def success(
|
|
19
18
|
self,
|
|
20
19
|
message,
|
|
21
|
-
title:
|
|
22
|
-
title_extra:
|
|
23
|
-
subtitle:
|
|
20
|
+
title: str | None = None,
|
|
21
|
+
title_extra: str | None = None,
|
|
22
|
+
subtitle: str | None = None,
|
|
24
23
|
):
|
|
25
24
|
if not title:
|
|
26
25
|
title = f"{PANEL_TITLE_SUCCESS}{f' - {title_extra}' if title_extra is not None else ''}"
|
|
@@ -39,9 +38,9 @@ class PipecatConsole(Console):
|
|
|
39
38
|
def error(
|
|
40
39
|
self,
|
|
41
40
|
message,
|
|
42
|
-
title:
|
|
43
|
-
title_extra:
|
|
44
|
-
subtitle:
|
|
41
|
+
title: str | None = None,
|
|
42
|
+
title_extra: str | None = None,
|
|
43
|
+
subtitle: str | None = None,
|
|
45
44
|
):
|
|
46
45
|
if not title:
|
|
47
46
|
title = f"{PANEL_TITLE_ERROR}{f' - {title_extra}' if title_extra is not None else ''}"
|
|
@@ -74,8 +73,8 @@ class PipecatConsole(Console):
|
|
|
74
73
|
|
|
75
74
|
def api_error(
|
|
76
75
|
self,
|
|
77
|
-
error_code:
|
|
78
|
-
title:
|
|
76
|
+
error_code: str | dict | None = None,
|
|
77
|
+
title: str | None = "API Error",
|
|
79
78
|
hide_subtitle: bool = False,
|
|
80
79
|
):
|
|
81
80
|
DEFAULT_ERROR_MESSAGE = "Unknown error. Please contact support."
|
|
@@ -6,10 +6,9 @@
|
|
|
6
6
|
|
|
7
7
|
import functools
|
|
8
8
|
import os
|
|
9
|
-
from
|
|
9
|
+
from collections.abc import Callable
|
|
10
|
+
from datetime import UTC, datetime
|
|
10
11
|
from enum import Enum
|
|
11
|
-
from typing import Callable, List, Optional
|
|
12
|
-
|
|
13
12
|
|
|
14
13
|
import toml
|
|
15
14
|
import typer
|
|
@@ -42,12 +41,12 @@ class DeploymentStatus:
|
|
|
42
41
|
status_message: str
|
|
43
42
|
is_available: bool = False
|
|
44
43
|
is_ready: bool = False
|
|
45
|
-
degraded_reason:
|
|
46
|
-
current_revision:
|
|
47
|
-
previous_revision:
|
|
44
|
+
degraded_reason: str | None = None
|
|
45
|
+
current_revision: dict | None = None
|
|
46
|
+
previous_revision: dict | None = None
|
|
48
47
|
|
|
49
48
|
|
|
50
|
-
def _find_condition(conditions: list, condition_type: str) ->
|
|
49
|
+
def _find_condition(conditions: list, condition_type: str) -> dict | None:
|
|
51
50
|
"""Find a condition by type from the conditions array."""
|
|
52
51
|
for c in conditions:
|
|
53
52
|
if c.get("type") == condition_type:
|
|
@@ -55,13 +54,13 @@ def _find_condition(conditions: list, condition_type: str) -> Optional[dict]:
|
|
|
55
54
|
return None
|
|
56
55
|
|
|
57
56
|
|
|
58
|
-
def _format_elapsed(phase_started_at:
|
|
57
|
+
def _format_elapsed(phase_started_at: str | None) -> str:
|
|
59
58
|
"""Format elapsed time since phaseStartedAt as a human-readable string."""
|
|
60
59
|
if not phase_started_at:
|
|
61
60
|
return ""
|
|
62
61
|
try:
|
|
63
62
|
started = datetime.fromisoformat(phase_started_at.replace("Z", "+00:00"))
|
|
64
|
-
elapsed = datetime.now(
|
|
63
|
+
elapsed = datetime.now(UTC) - started
|
|
65
64
|
total_seconds = int(elapsed.total_seconds())
|
|
66
65
|
if total_seconds < 0:
|
|
67
66
|
return ""
|
|
@@ -149,7 +148,7 @@ def _build_status_message(headline: str, current_rev=None, previous_rev=None) ->
|
|
|
149
148
|
|
|
150
149
|
def interpret_deployment_status(
|
|
151
150
|
agent_status: dict,
|
|
152
|
-
desired_deployment_id:
|
|
151
|
+
desired_deployment_id: str | None = None,
|
|
153
152
|
) -> DeploymentStatus:
|
|
154
153
|
"""Interpret the raw API response into a structured deployment status.
|
|
155
154
|
|
|
@@ -253,12 +252,12 @@ def interpret_deployment_status(
|
|
|
253
252
|
|
|
254
253
|
@dataclass
|
|
255
254
|
class ScalingParams:
|
|
256
|
-
min_agents:
|
|
257
|
-
max_agents:
|
|
255
|
+
min_agents: int | None = 0
|
|
256
|
+
max_agents: int | None = None
|
|
258
257
|
# @deprecated
|
|
259
|
-
min_instances:
|
|
258
|
+
min_instances: int | None = field(default=None, metadata={"deprecated": True})
|
|
260
259
|
# @deprecated
|
|
261
|
-
max_instances:
|
|
260
|
+
max_instances: int | None = field(default=None, metadata={"deprecated": True})
|
|
262
261
|
|
|
263
262
|
def __attrs_post_init__(self):
|
|
264
263
|
# Handle deprecated fields
|
|
@@ -288,7 +287,7 @@ class ScalingParams:
|
|
|
288
287
|
|
|
289
288
|
@dataclass
|
|
290
289
|
class KrispVivaConfig:
|
|
291
|
-
audio_filter:
|
|
290
|
+
audio_filter: KrispVivaAudioFilter | None = None
|
|
292
291
|
|
|
293
292
|
def __attrs_post_init__(self):
|
|
294
293
|
# Validation against known models
|
|
@@ -309,7 +308,7 @@ class BuildConfig:
|
|
|
309
308
|
|
|
310
309
|
context_dir: str = "."
|
|
311
310
|
dockerfile: str = "Dockerfile"
|
|
312
|
-
exclude_patterns:
|
|
311
|
+
exclude_patterns: list[str] = field(factory=list)
|
|
313
312
|
|
|
314
313
|
def to_dict(self):
|
|
315
314
|
return {
|
|
@@ -321,19 +320,21 @@ class BuildConfig:
|
|
|
321
320
|
|
|
322
321
|
@dataclass
|
|
323
322
|
class DeployConfigParams:
|
|
324
|
-
agent_name:
|
|
325
|
-
image:
|
|
326
|
-
build_id:
|
|
327
|
-
image_credentials:
|
|
328
|
-
secret_set:
|
|
329
|
-
region:
|
|
323
|
+
agent_name: str | None = None
|
|
324
|
+
image: str | None = None
|
|
325
|
+
build_id: str | None = None # For cloud builds
|
|
326
|
+
image_credentials: str | None = None
|
|
327
|
+
secret_set: str | None = None
|
|
328
|
+
region: str | None = None
|
|
330
329
|
scaling: ScalingParams = ScalingParams()
|
|
331
330
|
enable_krisp: bool = False
|
|
332
331
|
docker_config: dict = field(factory=dict)
|
|
333
332
|
build_config: BuildConfig = field(factory=BuildConfig) # Cloud build configuration
|
|
334
|
-
agent_profile:
|
|
333
|
+
agent_profile: str | None = None
|
|
335
334
|
krisp_viva: KrispVivaConfig = field(factory=KrispVivaConfig)
|
|
336
335
|
force_redeploy: bool = False
|
|
336
|
+
websocket_auth: str | None = None
|
|
337
|
+
max_session_duration: int | None = None
|
|
337
338
|
|
|
338
339
|
def __attrs_post_init__(self):
|
|
339
340
|
if self.image is not None and ":" not in self.image:
|
|
@@ -341,6 +342,8 @@ class DeployConfigParams:
|
|
|
341
342
|
# Cannot specify both image and build_id
|
|
342
343
|
if self.image is not None and self.build_id is not None:
|
|
343
344
|
raise ValueError("Cannot specify both 'image' and 'build_id'")
|
|
345
|
+
if self.max_session_duration is not None and not 60 <= self.max_session_duration <= 14400:
|
|
346
|
+
raise ValueError("max_session_duration must be between 60 and 14400 seconds")
|
|
344
347
|
|
|
345
348
|
def to_dict(self):
|
|
346
349
|
return {
|
|
@@ -356,17 +359,19 @@ class DeployConfigParams:
|
|
|
356
359
|
"build_config": self.build_config.to_dict() if self.build_config else None,
|
|
357
360
|
"agent_profile": self.agent_profile,
|
|
358
361
|
"krisp_viva": self.krisp_viva.to_dict() if self.krisp_viva else None,
|
|
362
|
+
"websocket_auth": self.websocket_auth,
|
|
363
|
+
"max_session_duration": self.max_session_duration,
|
|
359
364
|
}
|
|
360
365
|
|
|
361
366
|
|
|
362
|
-
def load_deploy_config_file() ->
|
|
367
|
+
def load_deploy_config_file() -> DeployConfigParams | None:
|
|
363
368
|
from pipecatcloud.cli.config import deploy_config_path
|
|
364
369
|
|
|
365
370
|
logger.debug(f"Deploy config path: {deploy_config_path}")
|
|
366
371
|
logger.debug(f"Deploy config path exists: {os.path.exists(deploy_config_path)}")
|
|
367
372
|
|
|
368
373
|
try:
|
|
369
|
-
with open(deploy_config_path
|
|
374
|
+
with open(deploy_config_path) as f:
|
|
370
375
|
config_data = toml.load(f)
|
|
371
376
|
except Exception:
|
|
372
377
|
return None
|
|
@@ -415,6 +420,8 @@ def load_deploy_config_file() -> Optional[DeployConfigParams]:
|
|
|
415
420
|
"build",
|
|
416
421
|
"agent_profile",
|
|
417
422
|
"krisp_viva",
|
|
423
|
+
"websocket_auth",
|
|
424
|
+
"max_session_duration",
|
|
418
425
|
}
|
|
419
426
|
unexpected_keys = set(config_data.keys()) - expected_keys
|
|
420
427
|
if unexpected_keys:
|
|
@@ -427,7 +434,7 @@ def load_deploy_config_file() -> Optional[DeployConfigParams]:
|
|
|
427
434
|
raise ConfigFileError(str(e))
|
|
428
435
|
|
|
429
436
|
|
|
430
|
-
CONFIG_FILE_OPTION:
|
|
437
|
+
CONFIG_FILE_OPTION: str | None = typer.Option(
|
|
431
438
|
None,
|
|
432
439
|
"--config-file",
|
|
433
440
|
help=f"Path to deploy config file (default: {PIPECAT_DEPLOY_CONFIG_PATH})",
|
|
@@ -459,8 +466,10 @@ def with_deploy_config(func: Callable) -> Callable:
|
|
|
459
466
|
deploy_config = load_deploy_config_file()
|
|
460
467
|
kwargs["deploy_config"] = deploy_config
|
|
461
468
|
except Exception as e:
|
|
462
|
-
|
|
463
|
-
|
|
469
|
+
from pipecatcloud._utils.console_utils import console
|
|
470
|
+
|
|
471
|
+
console.error(f"Error loading deploy config: {e}")
|
|
472
|
+
raise typer.Exit(1)
|
|
464
473
|
return func(*args, **kwargs)
|
|
465
474
|
|
|
466
475
|
return wrapper
|
|
@@ -10,16 +10,14 @@ Region utilities for Pipecat Cloud CLI.
|
|
|
10
10
|
Provides functions to fetch and cache available regions from the API.
|
|
11
11
|
"""
|
|
12
12
|
|
|
13
|
-
from typing import Dict, List, Optional
|
|
14
|
-
|
|
15
13
|
from pipecatcloud.cli.api import API
|
|
16
14
|
from pipecatcloud.cli.config import config
|
|
17
15
|
|
|
18
16
|
# Module-level cache for regions
|
|
19
|
-
_regions_cache:
|
|
17
|
+
_regions_cache: list[dict[str, str]] | None = None
|
|
20
18
|
|
|
21
19
|
|
|
22
|
-
async def get_regions() ->
|
|
20
|
+
async def get_regions() -> list[dict[str, str]]:
|
|
23
21
|
"""
|
|
24
22
|
Fetch available regions from the API with caching.
|
|
25
23
|
|
|
@@ -45,7 +43,7 @@ async def get_regions() -> List[Dict[str, str]]:
|
|
|
45
43
|
return _regions_cache
|
|
46
44
|
|
|
47
45
|
|
|
48
|
-
async def get_region_codes() ->
|
|
46
|
+
async def get_region_codes() -> list[str]:
|
|
49
47
|
"""
|
|
50
48
|
Get list of region codes only.
|
|
51
49
|
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
import warnings
|
|
8
8
|
from dataclasses import dataclass, field
|
|
9
|
-
from typing import Any
|
|
9
|
+
from typing import Any
|
|
10
10
|
|
|
11
11
|
from fastapi import WebSocket
|
|
12
12
|
|
|
@@ -36,7 +36,7 @@ except ImportError:
|
|
|
36
36
|
handle_sigint: bool = field(init=False, kw_only=True)
|
|
37
37
|
handle_sigterm: bool = field(init=False, kw_only=True)
|
|
38
38
|
pipeline_idle_timeout_secs: int = field(init=False, kw_only=True)
|
|
39
|
-
body:
|
|
39
|
+
body: Any | None = field(default_factory=dict, kw_only=True)
|
|
40
40
|
|
|
41
41
|
def __post_init__(self):
|
|
42
42
|
self.handle_sigint = False
|
|
@@ -94,11 +94,11 @@ class SessionArguments:
|
|
|
94
94
|
The arguments are received by the bot() entry point.
|
|
95
95
|
|
|
96
96
|
Parameters:
|
|
97
|
-
session_id (
|
|
97
|
+
session_id (str | None): The unique identifier for the session.
|
|
98
98
|
This is used to track the session across requests.
|
|
99
99
|
"""
|
|
100
100
|
|
|
101
|
-
session_id:
|
|
101
|
+
session_id: str | None
|
|
102
102
|
|
|
103
103
|
|
|
104
104
|
@dataclass
|