pipecatcloud 0.2.4__tar.gz → 0.2.6__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.2.4/.github/workflows/publish-test.yml → pipecatcloud-0.2.6/.github/workflows/publish-pypi.yml +30 -25
- pipecatcloud-0.2.6/.github/workflows/publish-test.yml +51 -0
- {pipecatcloud-0.2.4 → pipecatcloud-0.2.6}/CHANGELOG.md +30 -0
- {pipecatcloud-0.2.4/src/pipecatcloud.egg-info → pipecatcloud-0.2.6}/PKG-INFO +1 -1
- {pipecatcloud-0.2.4 → pipecatcloud-0.2.6}/pyproject.toml +5 -1
- {pipecatcloud-0.2.4 → pipecatcloud-0.2.6}/src/pipecatcloud/__init__.py +4 -0
- {pipecatcloud-0.2.4 → pipecatcloud-0.2.6}/src/pipecatcloud/_utils/deploy_utils.py +6 -0
- {pipecatcloud-0.2.4 → pipecatcloud-0.2.6}/src/pipecatcloud/agent.py +26 -0
- {pipecatcloud-0.2.4 → pipecatcloud-0.2.6}/src/pipecatcloud/api.py +2 -0
- {pipecatcloud-0.2.4 → pipecatcloud-0.2.6}/src/pipecatcloud/cli/commands/agent.py +87 -60
- {pipecatcloud-0.2.4 → pipecatcloud-0.2.6}/src/pipecatcloud/cli/commands/deploy.py +17 -0
- pipecatcloud-0.2.6/src/pipecatcloud/smallwebrtc/session_manager.py +87 -0
- {pipecatcloud-0.2.4 → pipecatcloud-0.2.6/src/pipecatcloud.egg-info}/PKG-INFO +1 -1
- {pipecatcloud-0.2.4 → pipecatcloud-0.2.6}/src/pipecatcloud.egg-info/SOURCES.txt +3 -2
- pipecatcloud-0.2.6/tests/test_managed_keys.py +420 -0
- pipecatcloud-0.2.4/.github/workflows/publish-pypi.yml +0 -84
- pipecatcloud-0.2.4/.github/workflows/python-publish.yml +0 -40
- {pipecatcloud-0.2.4 → pipecatcloud-0.2.6}/.github/workflows/tests.yml +0 -0
- {pipecatcloud-0.2.4 → pipecatcloud-0.2.6}/.gitignore +0 -0
- {pipecatcloud-0.2.4 → pipecatcloud-0.2.6}/LICENSE +0 -0
- {pipecatcloud-0.2.4 → pipecatcloud-0.2.6}/README.md +0 -0
- {pipecatcloud-0.2.4 → pipecatcloud-0.2.6}/pipecat-cloud.png +0 -0
- {pipecatcloud-0.2.4 → pipecatcloud-0.2.6}/pytest.ini +0 -0
- {pipecatcloud-0.2.4 → pipecatcloud-0.2.6}/setup.cfg +0 -0
- {pipecatcloud-0.2.4 → pipecatcloud-0.2.6}/src/pipecatcloud/__main__.py +0 -0
- {pipecatcloud-0.2.4 → pipecatcloud-0.2.6}/src/pipecatcloud/__version__.py +0 -0
- {pipecatcloud-0.2.4 → pipecatcloud-0.2.6}/src/pipecatcloud/_utils/__init__.py +0 -0
- {pipecatcloud-0.2.4 → pipecatcloud-0.2.6}/src/pipecatcloud/_utils/async_utils.py +0 -0
- {pipecatcloud-0.2.4 → pipecatcloud-0.2.6}/src/pipecatcloud/_utils/auth_utils.py +0 -0
- {pipecatcloud-0.2.4 → pipecatcloud-0.2.6}/src/pipecatcloud/_utils/console_utils.py +0 -0
- {pipecatcloud-0.2.4 → pipecatcloud-0.2.6}/src/pipecatcloud/_utils/local_runner.py +0 -0
- {pipecatcloud-0.2.4 → pipecatcloud-0.2.6}/src/pipecatcloud/cli/__init__.py +0 -0
- {pipecatcloud-0.2.4 → pipecatcloud-0.2.6}/src/pipecatcloud/cli/api.py +0 -0
- {pipecatcloud-0.2.4 → pipecatcloud-0.2.6}/src/pipecatcloud/cli/commands/__init__.py +0 -0
- {pipecatcloud-0.2.4 → pipecatcloud-0.2.6}/src/pipecatcloud/cli/commands/auth.py +0 -0
- {pipecatcloud-0.2.4 → pipecatcloud-0.2.6}/src/pipecatcloud/cli/commands/docker.py +0 -0
- {pipecatcloud-0.2.4 → pipecatcloud-0.2.6}/src/pipecatcloud/cli/commands/init.py +0 -0
- {pipecatcloud-0.2.4 → pipecatcloud-0.2.6}/src/pipecatcloud/cli/commands/organizations.py +0 -0
- {pipecatcloud-0.2.4 → pipecatcloud-0.2.6}/src/pipecatcloud/cli/commands/run.py +0 -0
- {pipecatcloud-0.2.4 → pipecatcloud-0.2.6}/src/pipecatcloud/cli/commands/secrets.py +0 -0
- {pipecatcloud-0.2.4 → pipecatcloud-0.2.6}/src/pipecatcloud/cli/config.py +0 -0
- {pipecatcloud-0.2.4 → pipecatcloud-0.2.6}/src/pipecatcloud/cli/entry_point.py +0 -0
- {pipecatcloud-0.2.4 → pipecatcloud-0.2.6}/src/pipecatcloud/config.py +0 -0
- {pipecatcloud-0.2.4 → pipecatcloud-0.2.6}/src/pipecatcloud/exception.py +0 -0
- {pipecatcloud-0.2.4 → pipecatcloud-0.2.6}/src/pipecatcloud/py.typed +0 -0
- {pipecatcloud-0.2.4 → pipecatcloud-0.2.6}/src/pipecatcloud/session.py +0 -0
- {pipecatcloud-0.2.4 → pipecatcloud-0.2.6}/src/pipecatcloud.egg-info/dependency_links.txt +0 -0
- {pipecatcloud-0.2.4 → pipecatcloud-0.2.6}/src/pipecatcloud.egg-info/entry_points.txt +0 -0
- {pipecatcloud-0.2.4 → pipecatcloud-0.2.6}/src/pipecatcloud.egg-info/requires.txt +0 -0
- {pipecatcloud-0.2.4 → pipecatcloud-0.2.6}/src/pipecatcloud.egg-info/top_level.txt +0 -0
- {pipecatcloud-0.2.4 → pipecatcloud-0.2.6}/tests/__init__.py +0 -0
- {pipecatcloud-0.2.4 → pipecatcloud-0.2.6}/tests/test_agent_sessions.py +0 -0
- {pipecatcloud-0.2.4 → pipecatcloud-0.2.6}/tests/test_docker_commands.py +0 -0
|
@@ -1,61 +1,67 @@
|
|
|
1
|
-
name: Publish to
|
|
1
|
+
name: Publish to PyPI
|
|
2
2
|
|
|
3
3
|
on:
|
|
4
4
|
workflow_dispatch:
|
|
5
5
|
inputs:
|
|
6
|
-
|
|
7
|
-
description: 'Version to publish (must match pyproject.toml, e.g. 0.0.4)'
|
|
8
|
-
required: true
|
|
6
|
+
gitref:
|
|
9
7
|
type: string
|
|
8
|
+
description: 'what git tag to build (e.g. v0.0.74)'
|
|
9
|
+
required: true
|
|
10
10
|
|
|
11
11
|
jobs:
|
|
12
12
|
build:
|
|
13
13
|
name: 'Build and upload wheels'
|
|
14
14
|
runs-on: ubuntu-latest
|
|
15
|
-
permissions:
|
|
16
|
-
contents: write
|
|
17
15
|
steps:
|
|
18
|
-
- name: Checkout
|
|
16
|
+
- name: Checkout repo
|
|
19
17
|
uses: actions/checkout@v4
|
|
20
18
|
with:
|
|
21
|
-
|
|
22
|
-
fetch-depth: 100
|
|
19
|
+
ref: ${{ github.event.inputs.gitref }}
|
|
23
20
|
|
|
24
21
|
- name: Install uv
|
|
25
22
|
uses: astral-sh/setup-uv@v3
|
|
26
23
|
with:
|
|
27
24
|
version: 'latest'
|
|
28
|
-
|
|
29
25
|
- name: Set up Python
|
|
30
26
|
run: uv python install 3.12
|
|
31
|
-
|
|
32
|
-
- name: Verify version matches
|
|
33
|
-
run: |
|
|
34
|
-
PROJECT_VERSION=$(uv run python -c "import tomllib; print(tomllib.load(open('pyproject.toml', 'rb'))['project']['version'])")
|
|
35
|
-
if [ "$PROJECT_VERSION" != "${{ github.event.inputs.version }}" ]; then
|
|
36
|
-
echo "Error: Input version (${{ github.event.inputs.version }}) does not match pyproject.toml version ($PROJECT_VERSION)"
|
|
37
|
-
exit 1
|
|
38
|
-
fi
|
|
39
|
-
|
|
40
27
|
- name: Install development dependencies
|
|
41
28
|
run: uv sync --group dev
|
|
42
|
-
|
|
43
29
|
- name: Build project
|
|
44
30
|
run: uv build
|
|
45
|
-
|
|
46
31
|
- name: Upload wheels
|
|
47
32
|
uses: actions/upload-artifact@v4
|
|
48
33
|
with:
|
|
49
34
|
name: wheels
|
|
50
35
|
path: ./dist
|
|
51
36
|
|
|
37
|
+
publish-to-pypi:
|
|
38
|
+
name: 'Publish to PyPI'
|
|
39
|
+
runs-on: ubuntu-latest
|
|
40
|
+
needs: [build]
|
|
41
|
+
environment:
|
|
42
|
+
name: pypi
|
|
43
|
+
url: https://pypi.org/p/pipecatcloud
|
|
44
|
+
permissions:
|
|
45
|
+
id-token: write
|
|
46
|
+
steps:
|
|
47
|
+
- name: Download wheels
|
|
48
|
+
uses: actions/download-artifact@v4
|
|
49
|
+
with:
|
|
50
|
+
name: wheels
|
|
51
|
+
path: ./dist
|
|
52
|
+
- name: Publish to PyPI
|
|
53
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
54
|
+
with:
|
|
55
|
+
verbose: true
|
|
56
|
+
print-hash: true
|
|
57
|
+
|
|
52
58
|
publish-to-test-pypi:
|
|
53
59
|
name: 'Publish to Test PyPI'
|
|
54
60
|
runs-on: ubuntu-latest
|
|
55
61
|
needs: [build]
|
|
56
62
|
environment:
|
|
57
63
|
name: testpypi
|
|
58
|
-
url: https://test.pypi.org/
|
|
64
|
+
url: https://test.pypi.org/p/pipecatcloud
|
|
59
65
|
permissions:
|
|
60
66
|
id-token: write
|
|
61
67
|
steps:
|
|
@@ -64,10 +70,9 @@ jobs:
|
|
|
64
70
|
with:
|
|
65
71
|
name: wheels
|
|
66
72
|
path: ./dist
|
|
67
|
-
|
|
68
|
-
- name: Publish to TestPyPI
|
|
73
|
+
- name: Publish to Test PyPI
|
|
69
74
|
uses: pypa/gh-action-pypi-publish@release/v1
|
|
70
75
|
with:
|
|
71
|
-
repository-url: https://test.pypi.org/legacy/
|
|
72
76
|
verbose: true
|
|
73
77
|
print-hash: true
|
|
78
|
+
repository-url: https://test.pypi.org/legacy/
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
name: Publish to TEST PyPI
|
|
2
|
+
|
|
3
|
+
on: workflow_dispatch
|
|
4
|
+
|
|
5
|
+
jobs:
|
|
6
|
+
build:
|
|
7
|
+
name: 'Build and upload wheels'
|
|
8
|
+
runs-on: ubuntu-latest
|
|
9
|
+
steps:
|
|
10
|
+
- name: Checkout repo
|
|
11
|
+
uses: actions/checkout@v4
|
|
12
|
+
with:
|
|
13
|
+
fetch-tags: true
|
|
14
|
+
fetch-depth: 100
|
|
15
|
+
- name: Install uv
|
|
16
|
+
uses: astral-sh/setup-uv@v3
|
|
17
|
+
with:
|
|
18
|
+
version: 'latest'
|
|
19
|
+
- name: Set up Python
|
|
20
|
+
run: uv python install 3.12
|
|
21
|
+
- name: Install development dependencies
|
|
22
|
+
run: uv sync --group dev
|
|
23
|
+
- name: Build project
|
|
24
|
+
run: uv build
|
|
25
|
+
- name: Upload wheels
|
|
26
|
+
uses: actions/upload-artifact@v4
|
|
27
|
+
with:
|
|
28
|
+
name: wheels
|
|
29
|
+
path: ./dist
|
|
30
|
+
|
|
31
|
+
publish-to-test-pypi:
|
|
32
|
+
name: 'Publish to Test PyPI'
|
|
33
|
+
runs-on: ubuntu-latest
|
|
34
|
+
needs: [build]
|
|
35
|
+
environment:
|
|
36
|
+
name: testpypi
|
|
37
|
+
url: https://test.pypi.org/p/pipecatcloud
|
|
38
|
+
permissions:
|
|
39
|
+
id-token: write
|
|
40
|
+
steps:
|
|
41
|
+
- name: Download wheels
|
|
42
|
+
uses: actions/download-artifact@v4
|
|
43
|
+
with:
|
|
44
|
+
name: wheels
|
|
45
|
+
path: ./dist
|
|
46
|
+
- name: Publish to Test PyPI
|
|
47
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
48
|
+
with:
|
|
49
|
+
verbose: true
|
|
50
|
+
print-hash: true
|
|
51
|
+
repository-url: https://test.pypi.org/legacy/
|
|
@@ -5,6 +5,36 @@ 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.2.6] - 2025-10-09
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Added an optional `--profile` option to the `deploy` command which selects between
|
|
13
|
+
`agent-1x`, with 0.5 vCPUs / 1 GB RAM, and `agent-2x`, with 1 vCPU / 2 GB RAM. The
|
|
14
|
+
default profile is `agent-1x`.
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
|
|
18
|
+
- Fixed an issue where the `agent status` CLI command would return incorrect
|
|
19
|
+
values for Min and Max Agents.
|
|
20
|
+
|
|
21
|
+
## [0.2.5] - 2025-10-02
|
|
22
|
+
|
|
23
|
+
### Added
|
|
24
|
+
|
|
25
|
+
- Added a `body` parameter to the fallback type, `WebsocketRunnerArguments`.
|
|
26
|
+
|
|
27
|
+
- Added `SmallWebRTCSessionManager`, a Session Manager to simplify bot creation
|
|
28
|
+
in Pipecat Cloud using `SmallWebRTCTransport`.
|
|
29
|
+
- Added a `SmallWebRTCSessionArguments` dataclass.
|
|
30
|
+
|
|
31
|
+
- `deploy` command now accepts a `--enable-managed-keys` flag which enables
|
|
32
|
+
properly configured agents to use Daily's API keys for supported upstream
|
|
33
|
+
services. This can also be enabled via `pcc-deploy.toml` by adding the
|
|
34
|
+
`enable_managed_keys` attribute and a boolean value.
|
|
35
|
+
|
|
36
|
+
- `agent status` now reflects the state of the managed keys feature.
|
|
37
|
+
|
|
8
38
|
## [0.2.4] - 2025-08-26
|
|
9
39
|
|
|
10
40
|
### Added
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "pipecatcloud"
|
|
7
|
-
|
|
7
|
+
dynamic = ["version"]
|
|
8
8
|
requires-python = ">=3.10"
|
|
9
9
|
description = "Cloud hosting for Pipecat AI applications"
|
|
10
10
|
license = { text = "BSD 2-Clause License" }
|
|
@@ -58,3 +58,7 @@ line-length = 100
|
|
|
58
58
|
|
|
59
59
|
[project.urls]
|
|
60
60
|
Website = "https://docs.pipecat.daily.co/"
|
|
61
|
+
|
|
62
|
+
[tool.setuptools_scm]
|
|
63
|
+
local_scheme = "no-local-version"
|
|
64
|
+
fallback_version = "0.0.0-dev"
|
|
@@ -13,6 +13,7 @@ from pipecatcloud.agent import (
|
|
|
13
13
|
DailySessionArguments,
|
|
14
14
|
PipecatSessionArguments,
|
|
15
15
|
SessionArguments,
|
|
16
|
+
SmallWebRTCRunnerArguments,
|
|
16
17
|
WebSocketSessionArguments,
|
|
17
18
|
)
|
|
18
19
|
from pipecatcloud.exception import (
|
|
@@ -25,6 +26,7 @@ from pipecatcloud.exception import (
|
|
|
25
26
|
InvalidError,
|
|
26
27
|
)
|
|
27
28
|
from pipecatcloud.session import Session, SessionParams
|
|
29
|
+
from pipecatcloud.smallwebrtc.session_manager import SmallWebRTCSessionManager
|
|
28
30
|
|
|
29
31
|
logger.remove()
|
|
30
32
|
logger.add(sys.stderr, level=str(os.getenv("PCC_LOG_LEVEL", "INFO")))
|
|
@@ -35,10 +37,12 @@ __all__ = [
|
|
|
35
37
|
"DailySessionArguments",
|
|
36
38
|
"PipecatSessionArguments",
|
|
37
39
|
"SessionArguments",
|
|
40
|
+
"SmallWebRTCRunnerArguments",
|
|
38
41
|
"WebSocketSessionArguments",
|
|
39
42
|
# Session classes
|
|
40
43
|
"Session",
|
|
41
44
|
"SessionParams",
|
|
45
|
+
"SmallWebRTCSessionManager",
|
|
42
46
|
# Exception classes
|
|
43
47
|
"AgentNotHealthyError",
|
|
44
48
|
"AgentStartError",
|
|
@@ -64,7 +64,9 @@ class DeployConfigParams:
|
|
|
64
64
|
secret_set: Optional[str] = None
|
|
65
65
|
scaling: ScalingParams = ScalingParams()
|
|
66
66
|
enable_krisp: bool = False
|
|
67
|
+
enable_managed_keys: bool = False
|
|
67
68
|
docker_config: dict = field(factory=dict)
|
|
69
|
+
agent_profile: Optional[str] = None
|
|
68
70
|
|
|
69
71
|
def __attrs_post_init__(self):
|
|
70
72
|
if self.image is not None and ":" not in self.image:
|
|
@@ -78,7 +80,9 @@ class DeployConfigParams:
|
|
|
78
80
|
"secret_set": self.secret_set,
|
|
79
81
|
"scaling": self.scaling.to_dict() if self.scaling else None,
|
|
80
82
|
"enable_krisp": self.enable_krisp,
|
|
83
|
+
"enable_managed_keys": self.enable_managed_keys,
|
|
81
84
|
"docker_config": self.docker_config,
|
|
85
|
+
"agent_profile": self.agent_profile,
|
|
82
86
|
}
|
|
83
87
|
|
|
84
88
|
|
|
@@ -117,7 +121,9 @@ def load_deploy_config_file() -> Optional[DeployConfigParams]:
|
|
|
117
121
|
"secret_set",
|
|
118
122
|
"scaling",
|
|
119
123
|
"enable_krisp",
|
|
124
|
+
"enable_managed_keys",
|
|
120
125
|
"docker",
|
|
126
|
+
"agent_profile",
|
|
121
127
|
}
|
|
122
128
|
unexpected_keys = set(config_data.keys()) - expected_keys
|
|
123
129
|
if unexpected_keys:
|
|
@@ -16,6 +16,7 @@ try:
|
|
|
16
16
|
DailyRunnerArguments,
|
|
17
17
|
RunnerArguments,
|
|
18
18
|
WebSocketRunnerArguments,
|
|
19
|
+
SmallWebRTCRunnerArguments,
|
|
19
20
|
)
|
|
20
21
|
|
|
21
22
|
_PIPECAT_RUNNER_TYPES_AVAILABLE = True
|
|
@@ -62,6 +63,17 @@ except ImportError:
|
|
|
62
63
|
"""
|
|
63
64
|
|
|
64
65
|
websocket: WebSocket
|
|
66
|
+
body: Any
|
|
67
|
+
|
|
68
|
+
@dataclass
|
|
69
|
+
class SmallWebRTCRunnerArguments(RunnerArguments):
|
|
70
|
+
"""Fallback Small WebRTC transport session arguments for the runner.
|
|
71
|
+
|
|
72
|
+
Parameters:
|
|
73
|
+
webrtc_connection: Pre-configured WebRTC peer connection
|
|
74
|
+
"""
|
|
75
|
+
|
|
76
|
+
webrtc_connection: Any
|
|
65
77
|
|
|
66
78
|
|
|
67
79
|
def _warn_standalone_usage():
|
|
@@ -131,3 +143,17 @@ class WebSocketSessionArguments(WebSocketRunnerArguments, SessionArguments):
|
|
|
131
143
|
def __post_init__(self):
|
|
132
144
|
WebSocketRunnerArguments.__post_init__(self)
|
|
133
145
|
_warn_standalone_usage()
|
|
146
|
+
|
|
147
|
+
@dataclass
|
|
148
|
+
class SmallWebRTCSessionArguments(SmallWebRTCRunnerArguments, SessionArguments):
|
|
149
|
+
"""SmallWebRTCTransport based agent session arguments.
|
|
150
|
+
|
|
151
|
+
Inherits from SmallWebRTCRunnerArguments for compatibility with pipecat-ai runner.
|
|
152
|
+
When pipecat-ai is not installed, uses a fallback implementation (deprecated).
|
|
153
|
+
|
|
154
|
+
For best compatibility, install: pip install pipecatcloud[pipecat]
|
|
155
|
+
"""
|
|
156
|
+
|
|
157
|
+
def __post_init__(self):
|
|
158
|
+
SmallWebRTCRunnerArguments.__post_init__(self)
|
|
159
|
+
_warn_standalone_usage()
|
|
@@ -321,6 +321,8 @@ class _API:
|
|
|
321
321
|
"maxAgents": deploy_config.scaling.max_agents,
|
|
322
322
|
},
|
|
323
323
|
"enableKrisp": deploy_config.enable_krisp,
|
|
324
|
+
"enableIntegratedKeysProxy": deploy_config.enable_managed_keys, # API expects this field name
|
|
325
|
+
"agentProfile": deploy_config.agent_profile,
|
|
324
326
|
}
|
|
325
327
|
|
|
326
328
|
# Remove None values recursively
|
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
#
|
|
6
6
|
|
|
7
7
|
import json
|
|
8
|
-
import statistics
|
|
9
8
|
from enum import Enum
|
|
10
9
|
|
|
11
10
|
import aiohttp
|
|
@@ -22,11 +21,16 @@ from rich.text import Text
|
|
|
22
21
|
|
|
23
22
|
from pipecatcloud._utils.async_utils import synchronizer
|
|
24
23
|
from pipecatcloud._utils.auth_utils import requires_login
|
|
25
|
-
from pipecatcloud._utils.console_utils import
|
|
24
|
+
from pipecatcloud._utils.console_utils import (
|
|
25
|
+
calculate_percentiles,
|
|
26
|
+
console,
|
|
27
|
+
format_duration,
|
|
28
|
+
format_timestamp,
|
|
29
|
+
)
|
|
30
|
+
from pipecatcloud._utils.deploy_utils import DeployConfigParams, with_deploy_config
|
|
26
31
|
from pipecatcloud.cli import PIPECAT_CLI_NAME
|
|
27
32
|
from pipecatcloud.cli.api import API
|
|
28
33
|
from pipecatcloud.cli.config import config
|
|
29
|
-
from pipecatcloud._utils.deploy_utils import with_deploy_config, DeployConfigParams
|
|
30
34
|
|
|
31
35
|
agent_cli = typer.Typer(name="agent", help="Agent management", no_args_is_help=True)
|
|
32
36
|
|
|
@@ -55,7 +59,8 @@ async def list(
|
|
|
55
59
|
if not data or len(data) == 0:
|
|
56
60
|
console.error(
|
|
57
61
|
f"[red]No agents found for namespace / organization '{org}'[/red]\n\n"
|
|
58
|
-
f"[dim]Please deploy an agent first using[/dim] [bold cyan]{PIPECAT_CLI_NAME} deploy[/bold cyan]"
|
|
62
|
+
f"[dim]Please deploy an agent first using[/dim] [bold cyan]{PIPECAT_CLI_NAME} deploy[/bold cyan]"
|
|
63
|
+
)
|
|
59
64
|
return typer.Exit(1)
|
|
60
65
|
|
|
61
66
|
else:
|
|
@@ -120,6 +125,15 @@ async def status(
|
|
|
120
125
|
"[bold]Image:[/bold]",
|
|
121
126
|
str(data.get("deployment", {}).get("manifest", {}).get("spec", {}).get("image", "N/A")),
|
|
122
127
|
)
|
|
128
|
+
|
|
129
|
+
# Display agent profile if available
|
|
130
|
+
agent_profile = data.get("agentProfile")
|
|
131
|
+
if agent_profile:
|
|
132
|
+
deployment_table.add_row(
|
|
133
|
+
"[bold]Agent Profile:[/bold]",
|
|
134
|
+
str(agent_profile),
|
|
135
|
+
)
|
|
136
|
+
|
|
123
137
|
deployment_table.add_row(
|
|
124
138
|
"[bold]Active Deployment ID:[/bold]",
|
|
125
139
|
str(data.get("activeDeploymentId", "N/A")),
|
|
@@ -133,16 +147,34 @@ async def status(
|
|
|
133
147
|
str(data.get("updatedAt", "N/A")),
|
|
134
148
|
)
|
|
135
149
|
|
|
150
|
+
# Check for Managed Keys status
|
|
151
|
+
# API returns integratedKeysProxy but we display as "Managed Keys"
|
|
152
|
+
integrated_keys = (
|
|
153
|
+
data.get("deployment", {})
|
|
154
|
+
.get("manifest", {})
|
|
155
|
+
.get("spec", {})
|
|
156
|
+
.get("integratedKeysProxy", {})
|
|
157
|
+
)
|
|
158
|
+
if isinstance(integrated_keys, dict):
|
|
159
|
+
integrated_keys_enabled = integrated_keys.get("enabled", False)
|
|
160
|
+
else:
|
|
161
|
+
integrated_keys_enabled = bool(integrated_keys)
|
|
162
|
+
|
|
163
|
+
deployment_table.add_row(
|
|
164
|
+
"[bold]Managed Keys:[/bold]",
|
|
165
|
+
"[green]Enabled[/green]" if integrated_keys_enabled else "[dim]Disabled[/dim]",
|
|
166
|
+
)
|
|
167
|
+
|
|
136
168
|
# Autoscaling info
|
|
137
169
|
autoscaling_data = data.get("autoScaling", None)
|
|
138
170
|
if autoscaling_data:
|
|
139
171
|
scaling_renderables = [
|
|
140
172
|
Panel(
|
|
141
|
-
f"[bold]Minimum Agents[/bold]\n{autoscaling_data.get('
|
|
173
|
+
f"[bold]Minimum Agents[/bold]\n{autoscaling_data.get('minReplicas', 0)}",
|
|
142
174
|
expand=True,
|
|
143
175
|
),
|
|
144
176
|
Panel(
|
|
145
|
-
f"[bold]Maximum Agents[/bold]\n{autoscaling_data.get('
|
|
177
|
+
f"[bold]Maximum Agents[/bold]\n{autoscaling_data.get('maxReplicas', 0)}",
|
|
146
178
|
expand=True,
|
|
147
179
|
),
|
|
148
180
|
]
|
|
@@ -205,9 +237,7 @@ async def status(
|
|
|
205
237
|
async def sessions(
|
|
206
238
|
deploy_config=typer.Option(None, hidden=True),
|
|
207
239
|
agent_name: str = typer.Argument(
|
|
208
|
-
None,
|
|
209
|
-
help="Name of the agent to list sessions for e.g. 'my-agent'",
|
|
210
|
-
show_default=False
|
|
240
|
+
None, help="Name of the agent to list sessions for e.g. 'my-agent'", show_default=False
|
|
211
241
|
),
|
|
212
242
|
session_id: str = typer.Option(
|
|
213
243
|
None,
|
|
@@ -220,7 +250,7 @@ async def sessions(
|
|
|
220
250
|
),
|
|
221
251
|
):
|
|
222
252
|
org = organization or config.get("org")
|
|
223
|
-
|
|
253
|
+
|
|
224
254
|
# Get agent name from argument or deploy config
|
|
225
255
|
if not agent_name:
|
|
226
256
|
if deploy_config and deploy_config.agent_name:
|
|
@@ -252,15 +282,17 @@ async def sessions(
|
|
|
252
282
|
for session in completed_sessions:
|
|
253
283
|
try:
|
|
254
284
|
from datetime import datetime
|
|
255
|
-
|
|
256
|
-
|
|
285
|
+
|
|
286
|
+
created_at = datetime.fromisoformat(session["createdAt"].replace("Z", "+00:00"))
|
|
287
|
+
ended_at = datetime.fromisoformat(session["endedAt"].replace("Z", "+00:00"))
|
|
257
288
|
duration_seconds = (ended_at - created_at).total_seconds()
|
|
258
289
|
durations.append(duration_seconds)
|
|
259
290
|
except BaseException:
|
|
260
291
|
continue
|
|
261
292
|
|
|
262
|
-
bot_start_times = [
|
|
263
|
-
|
|
293
|
+
bot_start_times = [
|
|
294
|
+
s["botStartSeconds"] for s in sessions_list if s.get("botStartSeconds") is not None
|
|
295
|
+
]
|
|
264
296
|
bot_start_metrics = calculate_percentiles(bot_start_times)
|
|
265
297
|
duration_metrics = calculate_percentiles(durations)
|
|
266
298
|
cold_starts_count = sum(1 for s in sessions_list if s.get("coldStart") is True)
|
|
@@ -305,8 +337,9 @@ async def sessions(
|
|
|
305
337
|
if session_id and session["sessionId"] != session_id:
|
|
306
338
|
continue
|
|
307
339
|
|
|
308
|
-
session_duration =
|
|
309
|
-
session["createdAt"], session["endedAt"]) or "[dim]N/A[/dim]"
|
|
340
|
+
session_duration = (
|
|
341
|
+
format_duration(session["createdAt"], session["endedAt"]) or "[dim]N/A[/dim]"
|
|
342
|
+
)
|
|
310
343
|
status = session.get("completionStatus", "")
|
|
311
344
|
if session["endedAt"]:
|
|
312
345
|
if status == "500":
|
|
@@ -321,14 +354,18 @@ async def sessions(
|
|
|
321
354
|
|
|
322
355
|
row_data = [
|
|
323
356
|
session["sessionId"],
|
|
324
|
-
format_timestamp(
|
|
325
|
-
|
|
326
|
-
format_timestamp(
|
|
327
|
-
session["endedAt"]) if session["endedAt"] else "[dim]N/A[/dim]",
|
|
357
|
+
format_timestamp(session["createdAt"]),
|
|
358
|
+
format_timestamp(session["endedAt"]) if session["endedAt"] else "[dim]N/A[/dim]",
|
|
328
359
|
session_duration,
|
|
329
360
|
status_display,
|
|
330
|
-
f"{session['botStartSeconds']}s"
|
|
331
|
-
|
|
361
|
+
f"{session['botStartSeconds']}s"
|
|
362
|
+
if session["botStartSeconds"] is not None
|
|
363
|
+
else "[dim]N/A[/dim]",
|
|
364
|
+
"[red]Yes[/red]"
|
|
365
|
+
if session["coldStart"] is True
|
|
366
|
+
else "No"
|
|
367
|
+
if session["coldStart"] is False
|
|
368
|
+
else "[dim]N/A[/dim]",
|
|
332
369
|
]
|
|
333
370
|
|
|
334
371
|
if is_cold_start:
|
|
@@ -338,10 +375,11 @@ async def sessions(
|
|
|
338
375
|
|
|
339
376
|
console.success(
|
|
340
377
|
Group(
|
|
341
|
-
Columns(
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
table
|
|
378
|
+
Columns(metric_renderables, equal=True)
|
|
379
|
+
if metric_renderables and not session_id
|
|
380
|
+
else "",
|
|
381
|
+
table,
|
|
382
|
+
),
|
|
345
383
|
title=f"Session data for agent {agent_name} [dim]({org})[/dim]",
|
|
346
384
|
)
|
|
347
385
|
|
|
@@ -378,32 +416,16 @@ class LogLevelColors(str, Enum):
|
|
|
378
416
|
@synchronizer.create_blocking
|
|
379
417
|
@requires_login
|
|
380
418
|
async def logs(
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
help="Level of logs to get"),
|
|
392
|
-
format: LogFormat = typer.Option(
|
|
393
|
-
LogFormat.TEXT,
|
|
394
|
-
"--format",
|
|
395
|
-
"-f",
|
|
396
|
-
help="Logs format"),
|
|
397
|
-
limit: int = typer.Option(
|
|
398
|
-
100,
|
|
399
|
-
"--limit",
|
|
400
|
-
"-n",
|
|
401
|
-
help="Number of logs to get"),
|
|
402
|
-
deployment_id: str = typer.Option(
|
|
403
|
-
None,
|
|
404
|
-
"--deployment",
|
|
405
|
-
"-d",
|
|
406
|
-
help="Filter logs by deployment ID"),
|
|
419
|
+
agent_name: str,
|
|
420
|
+
organization: str = typer.Option(
|
|
421
|
+
None, "--organization", "-o", help="Organization to get status of agent for"
|
|
422
|
+
),
|
|
423
|
+
level: LogLevel = typer.Option(None, "--level", "-l", help="Level of logs to get"),
|
|
424
|
+
format: LogFormat = typer.Option(LogFormat.TEXT, "--format", "-f", help="Logs format"),
|
|
425
|
+
limit: int = typer.Option(100, "--limit", "-n", help="Number of logs to get"),
|
|
426
|
+
deployment_id: str = typer.Option(
|
|
427
|
+
None, "--deployment", "-d", help="Filter logs by deployment ID"
|
|
428
|
+
),
|
|
407
429
|
):
|
|
408
430
|
org = organization or config.get("org")
|
|
409
431
|
|
|
@@ -413,7 +435,9 @@ async def logs(
|
|
|
413
435
|
f"[dim]Fetching logs for {status_text}: [bold]'{agent_name}'[/bold] with severity: [bold cyan]{level.value if level else 'ALL'}[/bold cyan][/dim]",
|
|
414
436
|
spinner="dots",
|
|
415
437
|
):
|
|
416
|
-
data, error = await API.agent_logs(
|
|
438
|
+
data, error = await API.agent_logs(
|
|
439
|
+
agent_name=agent_name, org=org, limit=limit, deployment_id=deployment_id
|
|
440
|
+
)
|
|
417
441
|
|
|
418
442
|
if not data or not data.get("logs"):
|
|
419
443
|
console.print("[dim]No logs found for agent[/dim]")
|
|
@@ -527,12 +551,13 @@ async def deployments(
|
|
|
527
551
|
table.add_column("Updated At")
|
|
528
552
|
|
|
529
553
|
for deployment in data["deployments"]:
|
|
554
|
+
spec = deployment.get("manifest", {}).get("spec", {})
|
|
530
555
|
table.add_row(
|
|
531
|
-
deployment
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
deployment
|
|
535
|
-
deployment
|
|
556
|
+
deployment.get("id", "N/A"),
|
|
557
|
+
spec.get("dailyNodeType", "N/A"),
|
|
558
|
+
spec.get("image", "N/A"),
|
|
559
|
+
deployment.get("createdAt", "N/A"),
|
|
560
|
+
deployment.get("updatedAt", "N/A"),
|
|
536
561
|
)
|
|
537
562
|
|
|
538
563
|
console.print(
|
|
@@ -624,7 +649,8 @@ async def start(
|
|
|
624
649
|
title="Public API Key Required",
|
|
625
650
|
title_align="left",
|
|
626
651
|
border_style="yellow",
|
|
627
|
-
)
|
|
652
|
+
)
|
|
653
|
+
)
|
|
628
654
|
|
|
629
655
|
return typer.Exit(1)
|
|
630
656
|
|
|
@@ -654,7 +680,8 @@ async def start(
|
|
|
654
680
|
title=f"[bold]Start Request for agent: {agent_name}[/bold]",
|
|
655
681
|
title_align="left",
|
|
656
682
|
border_style="yellow",
|
|
657
|
-
)
|
|
683
|
+
)
|
|
684
|
+
)
|
|
658
685
|
if not await questionary.confirm(
|
|
659
686
|
"Are you sure you want to start an active session for this agent?"
|
|
660
687
|
).ask_async():
|
|
@@ -279,6 +279,19 @@ def create_deploy_command(app: typer.Typer):
|
|
|
279
279
|
help="Enable Krisp integration for this deployment",
|
|
280
280
|
rich_help_panel="Deployment Configuration",
|
|
281
281
|
),
|
|
282
|
+
managed_keys: bool = typer.Option(
|
|
283
|
+
False,
|
|
284
|
+
"--enable-managed-keys",
|
|
285
|
+
help="Enable Managed Keys for this deployment",
|
|
286
|
+
rich_help_panel="Deployment Configuration",
|
|
287
|
+
),
|
|
288
|
+
profile: str = typer.Option(
|
|
289
|
+
None,
|
|
290
|
+
"--profile",
|
|
291
|
+
"-p",
|
|
292
|
+
help="Agent profile to use for deployment",
|
|
293
|
+
rich_help_panel="Deployment Configuration",
|
|
294
|
+
),
|
|
282
295
|
skip_confirm: bool = typer.Option(
|
|
283
296
|
False,
|
|
284
297
|
"--force",
|
|
@@ -345,6 +358,8 @@ def create_deploy_command(app: typer.Typer):
|
|
|
345
358
|
else partial_config.scaling.max_agents,
|
|
346
359
|
)
|
|
347
360
|
partial_config.enable_krisp = krisp or partial_config.enable_krisp
|
|
361
|
+
partial_config.enable_managed_keys = managed_keys or partial_config.enable_managed_keys
|
|
362
|
+
partial_config.agent_profile = profile or partial_config.agent_profile
|
|
348
363
|
|
|
349
364
|
# Assert agent name and image are provided
|
|
350
365
|
if not partial_config.agent_name:
|
|
@@ -381,7 +396,9 @@ def create_deploy_command(app: typer.Typer):
|
|
|
381
396
|
(f"[bold white]Organization:[/bold white] [green]{org}[/green]"),
|
|
382
397
|
(f"[bold white]Secret set:[/bold white] {'[dim]None[/dim]' if not partial_config.secret_set else '[green] '+ partial_config.secret_set + '[/green]'}"),
|
|
383
398
|
(f"[bold white]Image pull secret:[/bold white] {'[dim]None[/dim]' if not partial_config.image_credentials else '[green]' + partial_config.image_credentials + '[/green]'}"),
|
|
399
|
+
(f"[bold white]Agent profile:[/bold white] {'[dim]None[/dim]' if not partial_config.agent_profile else '[green]' + partial_config.agent_profile + '[/green]'}"),
|
|
384
400
|
(f"[bold white]Krisp:[/bold white] {'[dim]Disabled[/dim]' if not partial_config.enable_krisp else '[green]Enabled[/green]'}"),
|
|
401
|
+
(f"[bold white]Managed Keys:[/bold white] {'[dim]Disabled[/dim]' if not partial_config.enable_managed_keys else '[green]Enabled[/green]'}"),
|
|
385
402
|
"\n[dim]Scaling configuration:[/dim]",
|
|
386
403
|
table,
|
|
387
404
|
*
|