pipecatcloud 0.7.0__tar.gz → 0.7.2__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.7.2/.github/workflows/python-compatibility.yml +45 -0
- {pipecatcloud-0.7.0 → pipecatcloud-0.7.2}/CHANGELOG.md +29 -0
- {pipecatcloud-0.7.0 → pipecatcloud-0.7.2}/PKG-INFO +1 -1
- {pipecatcloud-0.7.0 → pipecatcloud-0.7.2}/src/pipecatcloud/cli/commands/agent.py +1 -1
- {pipecatcloud-0.7.0 → pipecatcloud-0.7.2}/src/pipecatcloud/cli/commands/deploy.py +66 -5
- {pipecatcloud-0.7.0 → pipecatcloud-0.7.2}/src/pipecatcloud/cli/commands/organizations.py +1 -1
- {pipecatcloud-0.7.0 → pipecatcloud-0.7.2}/src/pipecatcloud/cli/commands/secrets.py +2 -2
- {pipecatcloud-0.7.0 → pipecatcloud-0.7.2}/src/pipecatcloud.egg-info/PKG-INFO +1 -1
- {pipecatcloud-0.7.0 → pipecatcloud-0.7.2}/src/pipecatcloud.egg-info/SOURCES.txt +2 -0
- pipecatcloud-0.7.2/tests/test_deploy_poll.py +43 -0
- {pipecatcloud-0.7.0 → pipecatcloud-0.7.2}/tests/test_regions.py +1 -1
- {pipecatcloud-0.7.0 → pipecatcloud-0.7.2}/.claude/settings.json +0 -0
- {pipecatcloud-0.7.0 → pipecatcloud-0.7.2}/.github/workflows/format.yml +0 -0
- {pipecatcloud-0.7.0 → pipecatcloud-0.7.2}/.github/workflows/publish-pypi.yml +0 -0
- {pipecatcloud-0.7.0 → pipecatcloud-0.7.2}/.github/workflows/publish-test.yml +0 -0
- {pipecatcloud-0.7.0 → pipecatcloud-0.7.2}/.github/workflows/tests.yml +0 -0
- {pipecatcloud-0.7.0 → pipecatcloud-0.7.2}/.gitignore +0 -0
- {pipecatcloud-0.7.0 → pipecatcloud-0.7.2}/.pre-commit-config.yaml +0 -0
- {pipecatcloud-0.7.0 → pipecatcloud-0.7.2}/CLAUDE.md +0 -0
- {pipecatcloud-0.7.0 → pipecatcloud-0.7.2}/LICENSE +0 -0
- {pipecatcloud-0.7.0 → pipecatcloud-0.7.2}/README.md +0 -0
- {pipecatcloud-0.7.0 → pipecatcloud-0.7.2}/pipecat-cloud.png +0 -0
- {pipecatcloud-0.7.0 → pipecatcloud-0.7.2}/pyproject.toml +0 -0
- {pipecatcloud-0.7.0 → pipecatcloud-0.7.2}/pytest.ini +0 -0
- {pipecatcloud-0.7.0 → pipecatcloud-0.7.2}/scripts/fix-ruff.sh +0 -0
- {pipecatcloud-0.7.0 → pipecatcloud-0.7.2}/setup.cfg +0 -0
- {pipecatcloud-0.7.0 → pipecatcloud-0.7.2}/src/pipecatcloud/__init__.py +0 -0
- {pipecatcloud-0.7.0 → pipecatcloud-0.7.2}/src/pipecatcloud/__main__.py +0 -0
- {pipecatcloud-0.7.0 → pipecatcloud-0.7.2}/src/pipecatcloud/__version__.py +0 -0
- {pipecatcloud-0.7.0 → pipecatcloud-0.7.2}/src/pipecatcloud/_utils/__init__.py +0 -0
- {pipecatcloud-0.7.0 → pipecatcloud-0.7.2}/src/pipecatcloud/_utils/async_utils.py +0 -0
- {pipecatcloud-0.7.0 → pipecatcloud-0.7.2}/src/pipecatcloud/_utils/auth_utils.py +0 -0
- {pipecatcloud-0.7.0 → pipecatcloud-0.7.2}/src/pipecatcloud/_utils/build_utils.py +0 -0
- {pipecatcloud-0.7.0 → pipecatcloud-0.7.2}/src/pipecatcloud/_utils/console_utils.py +0 -0
- {pipecatcloud-0.7.0 → pipecatcloud-0.7.2}/src/pipecatcloud/_utils/deploy_utils.py +0 -0
- {pipecatcloud-0.7.0 → pipecatcloud-0.7.2}/src/pipecatcloud/_utils/regions.py +0 -0
- {pipecatcloud-0.7.0 → pipecatcloud-0.7.2}/src/pipecatcloud/agent.py +0 -0
- {pipecatcloud-0.7.0 → pipecatcloud-0.7.2}/src/pipecatcloud/api.py +0 -0
- {pipecatcloud-0.7.0 → pipecatcloud-0.7.2}/src/pipecatcloud/cli/__init__.py +0 -0
- {pipecatcloud-0.7.0 → pipecatcloud-0.7.2}/src/pipecatcloud/cli/api.py +0 -0
- {pipecatcloud-0.7.0 → pipecatcloud-0.7.2}/src/pipecatcloud/cli/commands/__init__.py +0 -0
- {pipecatcloud-0.7.0 → pipecatcloud-0.7.2}/src/pipecatcloud/cli/commands/auth.py +0 -0
- {pipecatcloud-0.7.0 → pipecatcloud-0.7.2}/src/pipecatcloud/cli/commands/build.py +0 -0
- {pipecatcloud-0.7.0 → pipecatcloud-0.7.2}/src/pipecatcloud/cli/commands/docker.py +0 -0
- {pipecatcloud-0.7.0 → pipecatcloud-0.7.2}/src/pipecatcloud/cli/commands/regions.py +0 -0
- {pipecatcloud-0.7.0 → pipecatcloud-0.7.2}/src/pipecatcloud/cli/config.py +0 -0
- {pipecatcloud-0.7.0 → pipecatcloud-0.7.2}/src/pipecatcloud/cli/entry_point.py +0 -0
- {pipecatcloud-0.7.0 → pipecatcloud-0.7.2}/src/pipecatcloud/config.py +0 -0
- {pipecatcloud-0.7.0 → pipecatcloud-0.7.2}/src/pipecatcloud/constants.py +0 -0
- {pipecatcloud-0.7.0 → pipecatcloud-0.7.2}/src/pipecatcloud/exception.py +0 -0
- {pipecatcloud-0.7.0 → pipecatcloud-0.7.2}/src/pipecatcloud/py.typed +0 -0
- {pipecatcloud-0.7.0 → pipecatcloud-0.7.2}/src/pipecatcloud/session.py +0 -0
- {pipecatcloud-0.7.0 → pipecatcloud-0.7.2}/src/pipecatcloud/smallwebrtc/session_manager.py +0 -0
- {pipecatcloud-0.7.0 → pipecatcloud-0.7.2}/src/pipecatcloud.egg-info/dependency_links.txt +0 -0
- {pipecatcloud-0.7.0 → pipecatcloud-0.7.2}/src/pipecatcloud.egg-info/entry_points.txt +0 -0
- {pipecatcloud-0.7.0 → pipecatcloud-0.7.2}/src/pipecatcloud.egg-info/requires.txt +0 -0
- {pipecatcloud-0.7.0 → pipecatcloud-0.7.2}/src/pipecatcloud.egg-info/top_level.txt +0 -0
- {pipecatcloud-0.7.0 → pipecatcloud-0.7.2}/tests/__init__.py +0 -0
- {pipecatcloud-0.7.0 → pipecatcloud-0.7.2}/tests/conftest.py +0 -0
- {pipecatcloud-0.7.0 → pipecatcloud-0.7.2}/tests/test_agent_sessions.py +0 -0
- {pipecatcloud-0.7.0 → pipecatcloud-0.7.2}/tests/test_agent_stop.py +0 -0
- {pipecatcloud-0.7.0 → pipecatcloud-0.7.2}/tests/test_api_client.py +0 -0
- {pipecatcloud-0.7.0 → pipecatcloud-0.7.2}/tests/test_auth.py +0 -0
- {pipecatcloud-0.7.0 → pipecatcloud-0.7.2}/tests/test_build_utils.py +0 -0
- {pipecatcloud-0.7.0 → pipecatcloud-0.7.2}/tests/test_config_file.py +0 -0
- {pipecatcloud-0.7.0 → pipecatcloud-0.7.2}/tests/test_deployment_status.py +0 -0
- {pipecatcloud-0.7.0 → pipecatcloud-0.7.2}/tests/test_docker_commands.py +0 -0
- {pipecatcloud-0.7.0 → pipecatcloud-0.7.2}/tests/test_krisp_viva.py +0 -0
- {pipecatcloud-0.7.0 → pipecatcloud-0.7.2}/tests/test_max_session_duration.py +0 -0
- {pipecatcloud-0.7.0 → pipecatcloud-0.7.2}/tests/test_pat_auth.py +0 -0
- {pipecatcloud-0.7.0 → pipecatcloud-0.7.2}/uv.lock +0 -0
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
name: python-compatibility
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
push:
|
|
6
|
+
branches:
|
|
7
|
+
- main
|
|
8
|
+
pull_request:
|
|
9
|
+
branches:
|
|
10
|
+
- '**'
|
|
11
|
+
|
|
12
|
+
concurrency:
|
|
13
|
+
group: python-compat-${{ github.event.pull_request.number || github.ref }}
|
|
14
|
+
cancel-in-progress: true
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
compat:
|
|
18
|
+
runs-on: ubuntu-latest
|
|
19
|
+
strategy:
|
|
20
|
+
fail-fast: false
|
|
21
|
+
matrix:
|
|
22
|
+
python-version: ['3.11', '3.12', '3.13', '3.14']
|
|
23
|
+
|
|
24
|
+
name: Python ${{ matrix.python-version }}
|
|
25
|
+
steps:
|
|
26
|
+
- name: Checkout repo
|
|
27
|
+
uses: actions/checkout@v4
|
|
28
|
+
|
|
29
|
+
- name: Install uv
|
|
30
|
+
uses: astral-sh/setup-uv@v3
|
|
31
|
+
with:
|
|
32
|
+
version: 'latest'
|
|
33
|
+
|
|
34
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
35
|
+
run: |
|
|
36
|
+
uv python install ${{ matrix.python-version }}
|
|
37
|
+
uv python pin ${{ matrix.python-version }}
|
|
38
|
+
|
|
39
|
+
- name: Install dependencies
|
|
40
|
+
run: uv sync --group dev
|
|
41
|
+
|
|
42
|
+
- name: Verify CLI loads
|
|
43
|
+
run: |
|
|
44
|
+
uv run python --version
|
|
45
|
+
uv run pcc --help
|
|
@@ -5,6 +5,35 @@ 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.7.2] - 2026-05-29
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- `pcc deploy` no longer crashes with `AttributeError: 'NoneType' object has
|
|
13
|
+
no attribute 'get'` when a status poll hits a transient API error (e.g. a
|
|
14
|
+
502 from a briefly-unavailable API pod). The poll loop now checks for the
|
|
15
|
+
error before reading the status payload, and transient failures (5xx,
|
|
16
|
+
network blips, a not-yet-visible service) are retried for up to 5
|
|
17
|
+
consecutive attempts before giving up. A successful poll resets that
|
|
18
|
+
budget, so an isolated blip no longer surfaces as a traceback or fails an
|
|
19
|
+
otherwise-successful deploy. Non-transient errors (4xx, auth) still abort
|
|
20
|
+
immediately.
|
|
21
|
+
|
|
22
|
+
## [0.7.1] - 2026-05-14
|
|
23
|
+
|
|
24
|
+
### Fixed
|
|
25
|
+
|
|
26
|
+
- The `pcc` CLI now imports cleanly under Python 3.14. Previously, two
|
|
27
|
+
Typer command callbacks were defined with the names `list` and `set`,
|
|
28
|
+
shadowing the builtins. Under PEP 649's lazy annotation evaluation in
|
|
29
|
+
3.14, a separate command annotated `secrets: list[str]` then resolved
|
|
30
|
+
`list` to the decorated `FunctionWithAio` object and failed with
|
|
31
|
+
`TypeError: 'FunctionWithAio' object is not subscriptable` at import
|
|
32
|
+
time, breaking every CLI entrypoint. The callbacks have been renamed
|
|
33
|
+
(`create_set`, `list_sets`, `list_agents`, `list_organizations`); the
|
|
34
|
+
user-facing command names (`pcc secrets set`, `pcc secrets list`,
|
|
35
|
+
`pcc agent list`, `pcc organizations list`) are unchanged.
|
|
36
|
+
|
|
8
37
|
## [0.7.0] - 2026-05-07
|
|
9
38
|
|
|
10
39
|
### Added
|
|
@@ -89,7 +89,7 @@ def format_cpu(millicores: int) -> str:
|
|
|
89
89
|
@agent_cli.command(name="list", help="List agents in an organization.")
|
|
90
90
|
@synchronizer.create_blocking
|
|
91
91
|
@requires_login
|
|
92
|
-
async def
|
|
92
|
+
async def list_agents(
|
|
93
93
|
organization: str = typer.Option(
|
|
94
94
|
None, "--organization", "-o", help="Organization to list agents for"
|
|
95
95
|
),
|
|
@@ -43,6 +43,31 @@ from pipecatcloud.constants import KRISP_VIVA_MODELS, Region
|
|
|
43
43
|
|
|
44
44
|
MAX_ALIVE_CHECKS = 120
|
|
45
45
|
ALIVE_CHECK_SLEEP = 5
|
|
46
|
+
# How many *consecutive* transient status-poll failures to tolerate before
|
|
47
|
+
# giving up. A single successful poll resets this budget, so this only trips on
|
|
48
|
+
# a sustained outage, not on isolated blips.
|
|
49
|
+
MAX_CONSECUTIVE_POLL_FAILURES = 5
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _poll_failure_is_transient(error: dict | None) -> bool:
|
|
53
|
+
"""Decide whether a failed status poll should be retried rather than aborting.
|
|
54
|
+
|
|
55
|
+
A status poll can fail in a few ways, and only some are worth retrying:
|
|
56
|
+
|
|
57
|
+
- **No error payload** (``error is None``): the request never received a
|
|
58
|
+
response (connection reset, timeout) or the service object isn't visible
|
|
59
|
+
yet. Always transient.
|
|
60
|
+
- **5xx**: a server-side blip (e.g. the 502 from PCC-867). Transient.
|
|
61
|
+
- **4xx or a non-numeric application code**: a real client/auth/config
|
|
62
|
+
problem that won't clear on its own. Not transient — abort.
|
|
63
|
+
"""
|
|
64
|
+
if not error:
|
|
65
|
+
return True
|
|
66
|
+
code = str(error.get("code", "")) if isinstance(error, dict) else ""
|
|
67
|
+
if code.isdigit():
|
|
68
|
+
return 500 <= int(code) <= 599
|
|
69
|
+
return False
|
|
70
|
+
|
|
46
71
|
|
|
47
72
|
# ----- Cloud Build Flow
|
|
48
73
|
|
|
@@ -356,6 +381,7 @@ async def _deploy(params: DeployConfigParams, org, force: bool = False):
|
|
|
356
381
|
is_ready = False
|
|
357
382
|
last_status = None
|
|
358
383
|
checks_performed = 0
|
|
384
|
+
consecutive_failures = 0
|
|
359
385
|
|
|
360
386
|
console.print(
|
|
361
387
|
f"[bold cyan]{'Updating' if existing_agent else 'Pushing'}[/bold cyan] deployment for agent '{params.agent_name}'"
|
|
@@ -375,6 +401,46 @@ async def _deploy(params: DeployConfigParams, org, force: bool = False):
|
|
|
375
401
|
|
|
376
402
|
logger.debug(f"Deployment status: {agent_status}")
|
|
377
403
|
|
|
404
|
+
# A failed poll returns (None, error). Handle that here, *before*
|
|
405
|
+
# touching agent_status, so a transient blip can't crash the
|
|
406
|
+
# deploy with an AttributeError on None. Transient failures (5xx,
|
|
407
|
+
# network, not-yet-visible service) are retried up to a small
|
|
408
|
+
# consecutive cap; non-transient ones (4xx/auth) abort right away.
|
|
409
|
+
if error or agent_status is None:
|
|
410
|
+
if _poll_failure_is_transient(error):
|
|
411
|
+
consecutive_failures += 1
|
|
412
|
+
if consecutive_failures <= MAX_CONSECUTIVE_POLL_FAILURES:
|
|
413
|
+
logger.debug(
|
|
414
|
+
"Transient status-poll failure "
|
|
415
|
+
f"({consecutive_failures}/{MAX_CONSECUTIVE_POLL_FAILURES}): "
|
|
416
|
+
f"{error}"
|
|
417
|
+
)
|
|
418
|
+
status.update(
|
|
419
|
+
"[dim]Waiting for deployment status "
|
|
420
|
+
"(retrying after a transient API error)...[/dim]"
|
|
421
|
+
)
|
|
422
|
+
await asyncio.sleep(ALIVE_CHECK_SLEEP)
|
|
423
|
+
checks_performed += 1
|
|
424
|
+
continue
|
|
425
|
+
# Sustained failures — the deploy itself may well have
|
|
426
|
+
# succeeded, so point the user at `agent status` rather
|
|
427
|
+
# than implying it failed.
|
|
428
|
+
status.stop()
|
|
429
|
+
console.error(
|
|
430
|
+
"Error checking deployment status: the API returned a "
|
|
431
|
+
f"transient error {MAX_CONSECUTIVE_POLL_FAILURES} times in a row.\n"
|
|
432
|
+
"Your deployment may still be in progress. Check it with "
|
|
433
|
+
f"`{PIPECAT_CLI_NAME} agent status {params.agent_name}`"
|
|
434
|
+
)
|
|
435
|
+
return typer.Exit()
|
|
436
|
+
# Non-transient error (4xx, auth, etc.) — abort immediately.
|
|
437
|
+
status.stop()
|
|
438
|
+
console.error("Error checking deployment status")
|
|
439
|
+
return typer.Exit()
|
|
440
|
+
|
|
441
|
+
# Successful poll — reset the transient-failure budget.
|
|
442
|
+
consecutive_failures = 0
|
|
443
|
+
|
|
378
444
|
# Look for any error messages in the agent status
|
|
379
445
|
# Exit out of the polling loop if we find an error
|
|
380
446
|
status_errors = agent_status.get("errors", [])
|
|
@@ -388,11 +454,6 @@ async def _deploy(params: DeployConfigParams, org, force: bool = False):
|
|
|
388
454
|
console.error(f"Deployment failed with an unknown error: {status_errors}")
|
|
389
455
|
return typer.Exit()
|
|
390
456
|
|
|
391
|
-
if error:
|
|
392
|
-
status.stop()
|
|
393
|
-
console.error("Error checking deployment status")
|
|
394
|
-
return typer.Exit()
|
|
395
|
-
|
|
396
457
|
# Capture the deployment ID for display
|
|
397
458
|
desired_deployment_id = agent_status.get(
|
|
398
459
|
"desiredDeploymentId", agent_status.get("activeDeploymentId")
|
|
@@ -96,7 +96,7 @@ async def select(organization: str = typer.Option(None, "--organization", "-o"))
|
|
|
96
96
|
@organization_cli.command(name="list", help="List organizations user is a member of.")
|
|
97
97
|
@synchronizer.create_blocking
|
|
98
98
|
@requires_login
|
|
99
|
-
async def
|
|
99
|
+
async def list_organizations():
|
|
100
100
|
current_org = config.get("org")
|
|
101
101
|
|
|
102
102
|
with console.status(
|
|
@@ -76,7 +76,7 @@ def validate_secret_name(name: str):
|
|
|
76
76
|
@secrets_cli.command(name="set", help="Create a new secret set for active organization")
|
|
77
77
|
@synchronizer.create_blocking
|
|
78
78
|
@requires_login
|
|
79
|
-
async def
|
|
79
|
+
async def create_set(
|
|
80
80
|
name: str = typer.Argument(help="Name of the secret set to create e.g. 'my-secret-set'"),
|
|
81
81
|
secrets: list[str] = typer.Argument(
|
|
82
82
|
None,
|
|
@@ -361,7 +361,7 @@ async def unset(
|
|
|
361
361
|
@secrets_cli.command(name="list", help="List secret sets and set keys")
|
|
362
362
|
@synchronizer.create_blocking
|
|
363
363
|
@requires_login
|
|
364
|
-
async def
|
|
364
|
+
async def list_sets(
|
|
365
365
|
name: str = typer.Argument(
|
|
366
366
|
None, help="Name of the secret set to list secrets from e.g. 'my-secret-set'"
|
|
367
367
|
),
|
|
@@ -12,6 +12,7 @@ uv.lock
|
|
|
12
12
|
.github/workflows/format.yml
|
|
13
13
|
.github/workflows/publish-pypi.yml
|
|
14
14
|
.github/workflows/publish-test.yml
|
|
15
|
+
.github/workflows/python-compatibility.yml
|
|
15
16
|
.github/workflows/tests.yml
|
|
16
17
|
scripts/fix-ruff.sh
|
|
17
18
|
src/pipecatcloud/__init__.py
|
|
@@ -59,6 +60,7 @@ tests/test_api_client.py
|
|
|
59
60
|
tests/test_auth.py
|
|
60
61
|
tests/test_build_utils.py
|
|
61
62
|
tests/test_config_file.py
|
|
63
|
+
tests/test_deploy_poll.py
|
|
62
64
|
tests/test_deployment_status.py
|
|
63
65
|
tests/test_docker_commands.py
|
|
64
66
|
tests/test_krisp_viva.py
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Unit tests for deploy status-poll failure handling (PCC-872).
|
|
3
|
+
|
|
4
|
+
The deploy poll loop must not crash when a status poll fails: `API.agent`
|
|
5
|
+
returns `(None, error)` on any non-2xx, so the loop has to classify the failure
|
|
6
|
+
before touching the (None) status payload. `_poll_failure_is_transient` is that
|
|
7
|
+
classifier — transient blips get retried, real problems abort.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from pipecatcloud.cli.commands.deploy import _poll_failure_is_transient
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class TestTransientFailures:
|
|
14
|
+
"""Failures that should be retried rather than failing the deploy."""
|
|
15
|
+
|
|
16
|
+
def test_no_error_payload_is_transient(self):
|
|
17
|
+
# Network-level failures (timeout, connection reset) and 200-without-body
|
|
18
|
+
# responses surface as (None, None) — no structured error at all.
|
|
19
|
+
assert _poll_failure_is_transient(None) is True
|
|
20
|
+
|
|
21
|
+
def test_502_bad_gateway_is_transient(self):
|
|
22
|
+
# The exact case from the ticket: API pod cycled by its liveness probe.
|
|
23
|
+
assert _poll_failure_is_transient({"error": "Bad Gateway", "code": "502"}) is True
|
|
24
|
+
|
|
25
|
+
def test_500_and_503_are_transient(self):
|
|
26
|
+
assert _poll_failure_is_transient({"code": "500"}) is True
|
|
27
|
+
assert _poll_failure_is_transient({"code": "503"}) is True
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class TestFatalFailures:
|
|
31
|
+
"""Failures that won't clear on their own and should abort the deploy."""
|
|
32
|
+
|
|
33
|
+
def test_4xx_is_fatal(self):
|
|
34
|
+
assert _poll_failure_is_transient({"error": "Unauthorized", "code": "401"}) is False
|
|
35
|
+
assert _poll_failure_is_transient({"error": "Not Found", "code": "404"}) is False
|
|
36
|
+
|
|
37
|
+
def test_non_numeric_application_code_is_fatal(self):
|
|
38
|
+
# Structured PCC errors carry codes like this rather than HTTP statuses.
|
|
39
|
+
assert _poll_failure_is_transient({"code": "AGENT_CONFIG_INVALID"}) is False
|
|
40
|
+
|
|
41
|
+
def test_missing_code_with_error_present_is_fatal(self):
|
|
42
|
+
# An error dict with no code we can classify: don't assume retryable.
|
|
43
|
+
assert _poll_failure_is_transient({"error": "something broke"}) is False
|
|
@@ -179,7 +179,7 @@ class TestCLIRegionValidation:
|
|
|
179
179
|
"""Secrets set should accept valid regions from API."""
|
|
180
180
|
# Arrange
|
|
181
181
|
from pipecatcloud._utils import regions
|
|
182
|
-
from pipecatcloud.cli.commands.secrets import
|
|
182
|
+
from pipecatcloud.cli.commands.secrets import create_set as secrets_set
|
|
183
183
|
|
|
184
184
|
regions._regions_cache = None
|
|
185
185
|
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|