pipecatcloud 0.0.11__tar.gz → 0.1.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.1.0/CHANGELOG.md +86 -0
- {pipecatcloud-0.0.11/src/pipecatcloud.egg-info → pipecatcloud-0.1.0}/PKG-INFO +1 -1
- {pipecatcloud-0.0.11 → pipecatcloud-0.1.0}/pyproject.toml +1 -1
- {pipecatcloud-0.0.11 → pipecatcloud-0.1.0}/src/pipecatcloud/api.py +10 -0
- {pipecatcloud-0.0.11 → pipecatcloud-0.1.0}/src/pipecatcloud/cli/__init__.py +1 -1
- {pipecatcloud-0.0.11 → pipecatcloud-0.1.0}/src/pipecatcloud/cli/commands/agent.py +9 -25
- {pipecatcloud-0.0.11 → pipecatcloud-0.1.0}/src/pipecatcloud/cli/commands/auth.py +23 -10
- {pipecatcloud-0.0.11 → pipecatcloud-0.1.0}/src/pipecatcloud/cli/commands/deploy.py +62 -82
- {pipecatcloud-0.0.11 → pipecatcloud-0.1.0}/src/pipecatcloud/cli/commands/init.py +2 -1
- {pipecatcloud-0.0.11 → pipecatcloud-0.1.0}/src/pipecatcloud/cli/commands/secrets.py +1 -1
- {pipecatcloud-0.0.11 → pipecatcloud-0.1.0}/src/pipecatcloud/cli/config.py +4 -3
- {pipecatcloud-0.0.11 → pipecatcloud-0.1.0}/src/pipecatcloud/config.py +1 -0
- {pipecatcloud-0.0.11 → pipecatcloud-0.1.0/src/pipecatcloud.egg-info}/PKG-INFO +1 -1
- {pipecatcloud-0.0.11 → pipecatcloud-0.1.0}/src/pipecatcloud.egg-info/SOURCES.txt +0 -2
- pipecatcloud-0.0.11/CHANGELOG.md +0 -188
- pipecatcloud-0.0.11/publish-pypi.yml +0 -59
- pipecatcloud-0.0.11/publish-test.yml +0 -59
- {pipecatcloud-0.0.11 → pipecatcloud-0.1.0}/.github/workflows/publish-pypi.yml +0 -0
- {pipecatcloud-0.0.11 → pipecatcloud-0.1.0}/.github/workflows/publish-test.yml +0 -0
- {pipecatcloud-0.0.11 → pipecatcloud-0.1.0}/.github/workflows/python-publish.yml +0 -0
- {pipecatcloud-0.0.11 → pipecatcloud-0.1.0}/.gitignore +0 -0
- {pipecatcloud-0.0.11 → pipecatcloud-0.1.0}/LICENSE +0 -0
- {pipecatcloud-0.0.11 → pipecatcloud-0.1.0}/README.md +0 -0
- {pipecatcloud-0.0.11 → pipecatcloud-0.1.0}/dev-requirements.txt +0 -0
- {pipecatcloud-0.0.11 → pipecatcloud-0.1.0}/pipecat-cloud.png +0 -0
- {pipecatcloud-0.0.11 → pipecatcloud-0.1.0}/setup.cfg +0 -0
- {pipecatcloud-0.0.11 → pipecatcloud-0.1.0}/src/pipecatcloud/__init__.py +0 -0
- {pipecatcloud-0.0.11 → pipecatcloud-0.1.0}/src/pipecatcloud/__main__.py +0 -0
- {pipecatcloud-0.0.11 → pipecatcloud-0.1.0}/src/pipecatcloud/__version__.py +0 -0
- {pipecatcloud-0.0.11 → pipecatcloud-0.1.0}/src/pipecatcloud/_utils/__init__.py +0 -0
- {pipecatcloud-0.0.11 → pipecatcloud-0.1.0}/src/pipecatcloud/_utils/async_utils.py +0 -0
- {pipecatcloud-0.0.11 → pipecatcloud-0.1.0}/src/pipecatcloud/_utils/auth_utils.py +0 -0
- {pipecatcloud-0.0.11 → pipecatcloud-0.1.0}/src/pipecatcloud/_utils/console_utils.py +0 -0
- {pipecatcloud-0.0.11 → pipecatcloud-0.1.0}/src/pipecatcloud/_utils/deploy_utils.py +0 -0
- {pipecatcloud-0.0.11 → pipecatcloud-0.1.0}/src/pipecatcloud/_utils/local_runner.py +0 -0
- {pipecatcloud-0.0.11 → pipecatcloud-0.1.0}/src/pipecatcloud/cli/api.py +0 -0
- {pipecatcloud-0.0.11 → pipecatcloud-0.1.0}/src/pipecatcloud/cli/commands/__init__.py +0 -0
- {pipecatcloud-0.0.11 → pipecatcloud-0.1.0}/src/pipecatcloud/cli/commands/organizations.py +0 -0
- {pipecatcloud-0.0.11 → pipecatcloud-0.1.0}/src/pipecatcloud/cli/commands/run.py +0 -0
- {pipecatcloud-0.0.11 → pipecatcloud-0.1.0}/src/pipecatcloud/cli/entry_point.py +0 -0
- {pipecatcloud-0.0.11 → pipecatcloud-0.1.0}/src/pipecatcloud/exception.py +0 -0
- {pipecatcloud-0.0.11 → pipecatcloud-0.1.0}/src/pipecatcloud/session.py +0 -0
- {pipecatcloud-0.0.11 → pipecatcloud-0.1.0}/src/pipecatcloud.egg-info/dependency_links.txt +0 -0
- {pipecatcloud-0.0.11 → pipecatcloud-0.1.0}/src/pipecatcloud.egg-info/entry_points.txt +0 -0
- {pipecatcloud-0.0.11 → pipecatcloud-0.1.0}/src/pipecatcloud.egg-info/requires.txt +0 -0
- {pipecatcloud-0.0.11 → pipecatcloud-0.1.0}/src/pipecatcloud.egg-info/top_level.txt +0 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# Pipecat Cloud Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to **Pipecat Cloud** will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [0.1.0] - 2025-03-05
|
|
9
|
+
|
|
10
|
+
- `pipecatcloud.toml` moved to `$HOME/.config/pipecatcloud/pipecatcloud.toml`
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- `pcc auth whoami` now shows the namespace Daily API key for convenience
|
|
15
|
+
|
|
16
|
+
## [0.0.11] - 2025-03-04
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
|
|
20
|
+
- `session.py` now returns the response body from the `start()` method.
|
|
21
|
+
|
|
22
|
+
### Fixed
|
|
23
|
+
|
|
24
|
+
- Fixed an issue in `session.py` where a bot wouldn't start due to malformed
|
|
25
|
+
`data`.
|
|
26
|
+
|
|
27
|
+
## [0.0.10] - 2025-03-04
|
|
28
|
+
|
|
29
|
+
### Added
|
|
30
|
+
|
|
31
|
+
- `init` convenience command will now populate the working directory with files
|
|
32
|
+
from the starter project.
|
|
33
|
+
|
|
34
|
+
- `agent log` allows for optional severity level filtering.
|
|
35
|
+
|
|
36
|
+
### Changed
|
|
37
|
+
|
|
38
|
+
- `agent status` and `deploy` no longer show superfluous data.
|
|
39
|
+
|
|
40
|
+
- `session.py` now correctly handles errors when starting agents.
|
|
41
|
+
|
|
42
|
+
- `secrets set` no longer prompts twice for confirmation if the secret set does
|
|
43
|
+
not exist.
|
|
44
|
+
|
|
45
|
+
### Removed
|
|
46
|
+
|
|
47
|
+
- `errors.py` removed as redundant (error message and code returned via API).
|
|
48
|
+
|
|
49
|
+
- `agent_utils.py` removed as redundant (error message and code returned via
|
|
50
|
+
API).
|
|
51
|
+
|
|
52
|
+
## [0.0.9] - 2025-02-27
|
|
53
|
+
|
|
54
|
+
### Added
|
|
55
|
+
|
|
56
|
+
- `agent status [agent-name]` now shows deployment info and scaling
|
|
57
|
+
configuration.
|
|
58
|
+
|
|
59
|
+
- `agent sessions [agent-name]` lists active session count for an agent (will
|
|
60
|
+
list session details in future).
|
|
61
|
+
|
|
62
|
+
- `agent start [agent-name] -D` now shows the Daily room URL (and token) to
|
|
63
|
+
join in the terminal output.
|
|
64
|
+
|
|
65
|
+
### Changed
|
|
66
|
+
|
|
67
|
+
- Changed CLI command from `pipecat` to `pipecatcloud` or `pcc`.
|
|
68
|
+
|
|
69
|
+
- `agent delete` prompts the user for confirmation first.
|
|
70
|
+
|
|
71
|
+
- `agent start` now checks the target deployment first to ensure it exists and
|
|
72
|
+
is in a healthy state.
|
|
73
|
+
|
|
74
|
+
- Changed the information order of `agent status` so the health badge is
|
|
75
|
+
clearly visible in terminal.
|
|
76
|
+
|
|
77
|
+
- `agent deploy` now defaults to "Y" for the confirmation prompts.
|
|
78
|
+
|
|
79
|
+
### Fixed
|
|
80
|
+
|
|
81
|
+
- Fixed lint error with payload data in `agent start`.
|
|
82
|
+
|
|
83
|
+
- Fixed a bug where `pcc-deploy.toml` files were required to be present.
|
|
84
|
+
|
|
85
|
+
- `deploy` command now correctly passes the secret set to the deployment from
|
|
86
|
+
the `pcc-deploy.toml` file.
|
|
@@ -168,6 +168,16 @@ class _API:
|
|
|
168
168
|
def organizations(self):
|
|
169
169
|
return self.create_api_method(self._organizations)
|
|
170
170
|
|
|
171
|
+
# Daily API Key
|
|
172
|
+
|
|
173
|
+
async def _organizations_daily_key(self, org) -> dict:
|
|
174
|
+
url = self.construct_api_url("daily_key_path").format(org=org)
|
|
175
|
+
return await self._base_request("GET", url) or {}
|
|
176
|
+
|
|
177
|
+
@property
|
|
178
|
+
def organizations_daily_key(self):
|
|
179
|
+
return self.create_api_method(self._organizations_daily_key)
|
|
180
|
+
|
|
171
181
|
# API Keys
|
|
172
182
|
|
|
173
183
|
async def _api_keys(self, org) -> dict:
|
|
@@ -41,18 +41,16 @@ async def list(
|
|
|
41
41
|
):
|
|
42
42
|
org = organization or config.get("org")
|
|
43
43
|
|
|
44
|
-
with console.status(f"Fetching agents for organization: [bold]'{org}'[/bold]", spinner="dots"):
|
|
44
|
+
with console.status(f"[dim]Fetching agents for organization: [bold]'{org}'[/bold][/dim]", spinner="dots"):
|
|
45
45
|
data, error = await API.agents(org=org)
|
|
46
46
|
|
|
47
|
-
print(data)
|
|
48
47
|
if error:
|
|
49
48
|
typer.Exit()
|
|
50
49
|
|
|
51
50
|
if not data or len(data) == 0:
|
|
52
51
|
console.error(
|
|
53
52
|
f"[red]No agents found for namespace / organization '{org}'[/red]\n\n"
|
|
54
|
-
f"[dim]Please deploy an agent first using[/dim] [bold cyan]{PIPECAT_CLI_NAME} deploy[/bold cyan]"
|
|
55
|
-
)
|
|
53
|
+
f"[dim]Please deploy an agent first using[/dim] [bold cyan]{PIPECAT_CLI_NAME} deploy[/bold cyan]")
|
|
56
54
|
return typer.Exit(1)
|
|
57
55
|
|
|
58
56
|
else:
|
|
@@ -441,8 +439,7 @@ async def start(
|
|
|
441
439
|
title="Public API Key Required",
|
|
442
440
|
title_align="left",
|
|
443
441
|
border_style="yellow",
|
|
444
|
-
)
|
|
445
|
-
)
|
|
442
|
+
))
|
|
446
443
|
|
|
447
444
|
return typer.Exit(1)
|
|
448
445
|
|
|
@@ -457,8 +454,7 @@ async def start(
|
|
|
457
454
|
title=f"[bold]Start Request for agent: {agent_name}[/bold]",
|
|
458
455
|
title_align="left",
|
|
459
456
|
border_style="yellow",
|
|
460
|
-
)
|
|
461
|
-
)
|
|
457
|
+
))
|
|
462
458
|
if not await questionary.confirm(
|
|
463
459
|
"Are you sure you want to start an active session for this agent?"
|
|
464
460
|
).ask_async():
|
|
@@ -472,7 +468,7 @@ async def start(
|
|
|
472
468
|
if not health_data or not health_data["ready"]:
|
|
473
469
|
live.stop()
|
|
474
470
|
console.error(
|
|
475
|
-
f"Agent '{agent_name}' does not exist or is not in a
|
|
471
|
+
f"Agent '{agent_name}' does not exist or is not in a healthy state. Please check the agent status with [bold cyan]{PIPECAT_CLI_NAME} agent status {agent_name}[/bold cyan]"
|
|
476
472
|
)
|
|
477
473
|
return typer.Exit(1)
|
|
478
474
|
|
|
@@ -494,25 +490,13 @@ async def start(
|
|
|
494
490
|
if error:
|
|
495
491
|
return typer.Exit(1)
|
|
496
492
|
|
|
497
|
-
if not data:
|
|
498
|
-
live.stop()
|
|
499
|
-
console.error(
|
|
500
|
-
f"Agent '{agent_name}' not found. Have you deployed the agent?",
|
|
501
|
-
subtitle=f"[white dim]Deploy an agent with[/white dim] [bold cyan]{PIPECAT_CLI_NAME} deploy[/bold cyan]",
|
|
502
|
-
)
|
|
503
|
-
return typer.Exit(1)
|
|
504
|
-
|
|
505
493
|
live.stop()
|
|
506
494
|
|
|
507
|
-
|
|
495
|
+
console.success(f"Agent '{agent_name}' started successfully")
|
|
508
496
|
if use_daily and isinstance(data, dict):
|
|
509
497
|
daily_room = data.get("dailyRoom")
|
|
510
498
|
daily_token = data.get("dailyToken")
|
|
511
499
|
if daily_room:
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
subtitle=f"[white dim]Join the session:[/white dim] [link={daily_room}?t={daily_token}]click here[/link]",
|
|
516
|
-
)
|
|
517
|
-
|
|
518
|
-
console.success(message)
|
|
500
|
+
url = f"{daily_room}?t={daily_token}"
|
|
501
|
+
console.print("\nJoin your session by visiting the link below:")
|
|
502
|
+
console.print(f"[link='{url}']{url}[/link]")
|
|
@@ -13,6 +13,7 @@ from typing import AsyncGenerator, Optional, Tuple
|
|
|
13
13
|
import aiohttp
|
|
14
14
|
import typer
|
|
15
15
|
from loguru import logger
|
|
16
|
+
from rich.columns import Columns
|
|
16
17
|
from rich.live import Live
|
|
17
18
|
from rich.panel import Panel
|
|
18
19
|
|
|
@@ -151,10 +152,7 @@ async def login():
|
|
|
151
152
|
Panel(
|
|
152
153
|
"The web browser should have opened for you to authenticate with Pipecat Cloud.\n"
|
|
153
154
|
"If it didn't, please copy this URL into your web browser manually:\n\n"
|
|
154
|
-
f"[blue][link={web_url}]{web_url}[/link][/blue]\n",
|
|
155
|
-
)
|
|
156
|
-
)
|
|
157
|
-
)
|
|
155
|
+
f"[blue][link={web_url}]{web_url}[/link][/blue]\n", )))
|
|
158
156
|
else:
|
|
159
157
|
# For headless use-cases, just print the URL
|
|
160
158
|
live.stop()
|
|
@@ -222,7 +220,7 @@ async def logout():
|
|
|
222
220
|
)
|
|
223
221
|
|
|
224
222
|
|
|
225
|
-
@auth_cli.command(name="whoami", help="Display data about the current user.")
|
|
223
|
+
@auth_cli.command(name="whoami", help="Display data about the current user. Also show Daily API key.")
|
|
226
224
|
@synchronizer.create_blocking
|
|
227
225
|
@requires_login
|
|
228
226
|
async def whomai():
|
|
@@ -251,11 +249,26 @@ async def whomai():
|
|
|
251
249
|
if not account["name"] or not account["verbose_name"]:
|
|
252
250
|
raise
|
|
253
251
|
|
|
254
|
-
|
|
252
|
+
# Retrieve user Daily API key
|
|
253
|
+
# Note: we don't raise an error if this fails, as it's not required for
|
|
254
|
+
# the CLI to function
|
|
255
|
+
live.update(console.status("[dim]Fetching Daily API key...[/dim]", spinner="dots"))
|
|
255
256
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
257
|
+
daily_api_key = None
|
|
258
|
+
try:
|
|
259
|
+
daily_api_key, error = await API.organizations_daily_key(org=org, live=live)
|
|
260
|
+
except Exception:
|
|
261
|
+
pass
|
|
262
|
+
|
|
263
|
+
live.stop()
|
|
264
|
+
message = Columns([
|
|
265
|
+
"[bold]User ID[/bold]\n"
|
|
266
|
+
"[bold]Active Organization[/bold]\n"
|
|
267
|
+
"[bold]Daily API Key[/bold]",
|
|
268
|
+
f"{user_data['user']['userId']}\n"
|
|
269
|
+
f"{account['verbose_name']} [dim]({account['name']})[/dim]\n"
|
|
270
|
+
f"{daily_api_key.get('apiKey', '[dim]N/A[/dim]') if daily_api_key else '[dim]N/A[/dim]'}",
|
|
271
|
+
])
|
|
272
|
+
console.success(message)
|
|
260
273
|
except Exception:
|
|
261
274
|
console.error("Unable to obtain user data. Please contact support")
|
|
@@ -9,7 +9,6 @@ import asyncio
|
|
|
9
9
|
import typer
|
|
10
10
|
from rich.console import Group
|
|
11
11
|
from rich.live import Live
|
|
12
|
-
from rich.padding import Padding
|
|
13
12
|
from rich.panel import Panel
|
|
14
13
|
from rich.table import Table
|
|
15
14
|
from rich.text import Text
|
|
@@ -26,7 +25,7 @@ from pipecatcloud.cli import PIPECAT_CLI_NAME
|
|
|
26
25
|
from pipecatcloud.cli.api import API
|
|
27
26
|
from pipecatcloud.cli.config import config
|
|
28
27
|
|
|
29
|
-
MAX_ALIVE_CHECKS =
|
|
28
|
+
MAX_ALIVE_CHECKS = 30
|
|
30
29
|
ALIVE_CHECK_SLEEP = 5
|
|
31
30
|
|
|
32
31
|
# ----- Command
|
|
@@ -37,7 +36,7 @@ async def _deploy(params: DeployConfigParams, org, force: bool = False):
|
|
|
37
36
|
|
|
38
37
|
# Check for an existing deployment with this agent name
|
|
39
38
|
with Live(
|
|
40
|
-
console.status("[dim]Checking for existing agent deployment...[/dim]", spinner="dots")
|
|
39
|
+
console.status("[dim]Checking for existing agent deployment...[/dim]", spinner="dots"), transient=True
|
|
41
40
|
) as live:
|
|
42
41
|
data, error = await API.agent(agent_name=params.agent_name, org=org, live=live)
|
|
43
42
|
|
|
@@ -108,7 +107,7 @@ async def _deploy(params: DeployConfigParams, org, force: bool = False):
|
|
|
108
107
|
|
|
109
108
|
live.update(
|
|
110
109
|
console.status(
|
|
111
|
-
f"[dim]{'Updating' if existing_agent else 'Pushing'} agent manifest
|
|
110
|
+
f"[dim]{'Updating' if existing_agent else 'Pushing'} agent manifest for[/dim] [cyan]'{params.agent_name}'[/cyan]"
|
|
112
111
|
)
|
|
113
112
|
)
|
|
114
113
|
|
|
@@ -124,85 +123,73 @@ async def _deploy(params: DeployConfigParams, org, force: bool = False):
|
|
|
124
123
|
console.error("A problem occured during deployment. Please contact support.")
|
|
125
124
|
return typer.Exit()
|
|
126
125
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
"""
|
|
130
|
-
attempts = 0
|
|
131
|
-
active_deployment_id = None
|
|
132
|
-
has_failed = False
|
|
133
|
-
is_ready = False
|
|
134
|
-
|
|
135
|
-
while attempts < MAX_ALIVE_CHECKS:
|
|
136
|
-
status_render_group = Panel.fit(
|
|
137
|
-
Group(
|
|
138
|
-
Padding(
|
|
139
|
-
console.status(
|
|
140
|
-
f"[dim]Watching for deployment status (attempt: {attempts + 1})[dim]"
|
|
141
|
-
if not active_deployment_id
|
|
142
|
-
else f"Waiting for deployment to enter ready state [dim](attempt: {attempts + 1})[/dim]",
|
|
143
|
-
spinner="bouncingBar",
|
|
144
|
-
),
|
|
145
|
-
(1, 0),
|
|
146
|
-
)
|
|
147
|
-
),
|
|
148
|
-
title=f"[bold]{'Deploying' if not existing_agent else 'Updating'} agent[/bold]",
|
|
149
|
-
border_style="dim" if not active_deployment_id else "white",
|
|
150
|
-
subtitle=f"[dim]ID: {'Waiting...' if not active_deployment_id else active_deployment_id}[/dim]",
|
|
151
|
-
)
|
|
152
|
-
try:
|
|
153
|
-
await asyncio.sleep(ALIVE_CHECK_SLEEP)
|
|
154
|
-
|
|
155
|
-
live.update(status_render_group)
|
|
156
|
-
|
|
157
|
-
if has_failed:
|
|
158
|
-
break
|
|
126
|
+
# Close the live display before starting the new polling phase
|
|
127
|
+
live.stop()
|
|
159
128
|
|
|
160
|
-
|
|
129
|
+
"""
|
|
130
|
+
# 3. Poll status until healthy
|
|
131
|
+
"""
|
|
132
|
+
active_deployment_id = None
|
|
133
|
+
has_failed = False
|
|
134
|
+
is_ready = False
|
|
135
|
+
checks_performed = 0
|
|
136
|
+
|
|
137
|
+
# Create a simple spinner for the polling phase
|
|
138
|
+
with console.status(
|
|
139
|
+
"[dim]Waiting for deployment to become ready...[/dim]", spinner="bouncingBar"
|
|
140
|
+
) as status:
|
|
141
|
+
try:
|
|
142
|
+
while checks_performed < MAX_ALIVE_CHECKS:
|
|
143
|
+
# Get deployment status
|
|
144
|
+
agent_status, error = await API.agent(
|
|
145
|
+
agent_name=params.agent_name, org=org, live=None
|
|
146
|
+
)
|
|
161
147
|
|
|
162
148
|
if error:
|
|
149
|
+
status.stop()
|
|
150
|
+
console.error("Error checking deployment status")
|
|
163
151
|
return typer.Exit()
|
|
164
152
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
active_deployment_id = status["activeDeploymentId"]
|
|
153
|
+
# Update deployment ID if received (silently)
|
|
154
|
+
if not active_deployment_id and agent_status.get("activeDeploymentId"):
|
|
155
|
+
active_deployment_id = agent_status["activeDeploymentId"]
|
|
169
156
|
|
|
170
|
-
#
|
|
171
|
-
if
|
|
172
|
-
live.update("")
|
|
157
|
+
# Check if deployment is ready
|
|
158
|
+
if agent_status.get("ready"):
|
|
173
159
|
is_ready = True
|
|
174
160
|
break
|
|
175
161
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
"\n[yellow]Deployment monitoring interrupted. The deployment may still be in progress.[/yellow]"
|
|
180
|
-
)
|
|
181
|
-
return typer.Exit()
|
|
182
|
-
|
|
183
|
-
attempts += 1
|
|
184
|
-
|
|
185
|
-
live.stop()
|
|
186
|
-
|
|
187
|
-
if has_failed:
|
|
188
|
-
console.print(has_failed["message"])
|
|
189
|
-
console.error("Deployment failed with the above error")
|
|
190
|
-
return typer.Exit()
|
|
162
|
+
# Wait before checking again
|
|
163
|
+
await asyncio.sleep(ALIVE_CHECK_SLEEP)
|
|
164
|
+
checks_performed += 1
|
|
191
165
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
f"[bold]`{PIPECAT_CLI_NAME} agent start {params.agent_name}`[/bold]",
|
|
197
|
-
title_extra=f"{'Update'if existing_agent else 'Deployment'} complete",
|
|
198
|
-
)
|
|
199
|
-
else:
|
|
200
|
-
console.error(
|
|
201
|
-
f"Deployment did not enter ready state. Please check logs `{PIPECAT_CLI_NAME} agent logs {params.agent_name}`"
|
|
166
|
+
except KeyboardInterrupt:
|
|
167
|
+
status.stop()
|
|
168
|
+
console.print(
|
|
169
|
+
"\n[yellow]Deployment monitoring interrupted. The deployment may still be in progress.[/yellow]"
|
|
202
170
|
)
|
|
171
|
+
return typer.Exit()
|
|
203
172
|
|
|
173
|
+
# Final result handling
|
|
174
|
+
if has_failed:
|
|
175
|
+
console.print(has_failed["message"])
|
|
176
|
+
console.error("Deployment failed with the above error")
|
|
204
177
|
return typer.Exit()
|
|
205
178
|
|
|
179
|
+
if is_ready:
|
|
180
|
+
console.success(
|
|
181
|
+
f"Agent deployment [bold]'{params.agent_name}'[/bold] is ready\n\n"
|
|
182
|
+
f"[dim]Start a session with your new agent by running:\n[/dim]"
|
|
183
|
+
f"[bold]`{PIPECAT_CLI_NAME} agent start {params.agent_name}`[/bold]",
|
|
184
|
+
title_extra=f"{'Update' if existing_agent else 'Deployment'} complete",
|
|
185
|
+
)
|
|
186
|
+
else:
|
|
187
|
+
console.error(
|
|
188
|
+
f"Deployment did not enter ready state within {MAX_ALIVE_CHECKS * ALIVE_CHECK_SLEEP} seconds. "
|
|
189
|
+
f"Please check logs with `{PIPECAT_CLI_NAME} agent logs {params.agent_name}`")
|
|
190
|
+
|
|
191
|
+
return typer.Exit()
|
|
192
|
+
|
|
206
193
|
|
|
207
194
|
def create_deploy_command(app: typer.Typer):
|
|
208
195
|
@app.command(name="deploy", help="Deploy agent to Pipecat Cloud")
|
|
@@ -312,24 +299,17 @@ def create_deploy_command(app: typer.Typer):
|
|
|
312
299
|
(f"[bold white]Agent name:[/bold white] [green]{partial_config.agent_name}[/green]"),
|
|
313
300
|
(f"[bold white]Image:[/bold white] [green]{partial_config.image}[/green]"),
|
|
314
301
|
(f"[bold white]Organization:[/bold white] [green]{org}[/green]"),
|
|
315
|
-
(
|
|
316
|
-
|
|
317
|
-
),
|
|
318
|
-
(
|
|
319
|
-
f"[bold white]Image pull secret:[/bold white] {'[dim]None[/dim]' if not partial_config.image_credentials else '[green]' + partial_config.image_credentials + '[/green]'}"
|
|
320
|
-
),
|
|
302
|
+
(f"[bold white]Secret set:[/bold white] {'[dim]None[/dim]' if not partial_config.secret_set else '[green] '+ partial_config.secret_set + '[/green]'}"),
|
|
303
|
+
(f"[bold white]Image pull secret:[/bold white] {'[dim]None[/dim]' if not partial_config.image_credentials else '[green]' + partial_config.image_credentials + '[/green]'}"),
|
|
321
304
|
"\n[dim]Scaling configuration:[/dim]",
|
|
322
305
|
table,
|
|
323
|
-
*
|
|
324
|
-
|
|
325
|
-
if partial_config.scaling.min_instances
|
|
326
|
-
else [
|
|
306
|
+
*
|
|
307
|
+
(
|
|
308
|
+
[] if partial_config.scaling.min_instances else [
|
|
327
309
|
Text(
|
|
328
310
|
"Note: Deploying with 0 minimum instances may result in cold starts",
|
|
329
311
|
style="red",
|
|
330
|
-
)
|
|
331
|
-
]
|
|
332
|
-
),
|
|
312
|
+
)]),
|
|
333
313
|
)
|
|
334
314
|
|
|
335
315
|
console.print(
|
|
@@ -24,7 +24,8 @@ FILES_TO_EXTRACT = {
|
|
|
24
24
|
"pipecat-cloud-starter-main/requirements.txt",
|
|
25
25
|
"pipecat-cloud-starter-main/pcc-deploy.toml",
|
|
26
26
|
"pipecat-cloud-starter-main/README.md",
|
|
27
|
-
"pipecat-cloud-starter-main
|
|
27
|
+
"pipecat-cloud-starter-main/.gitignore",
|
|
28
|
+
"pipecat-cloud-starter-main/env.example",
|
|
28
29
|
"pipecat-cloud-starter-main/local_runner.py",
|
|
29
30
|
}
|
|
30
31
|
|
|
@@ -247,7 +247,7 @@ async def set(
|
|
|
247
247
|
action = "created" if not existing_set else "modified"
|
|
248
248
|
message = f"Secret set [bold green]'{name}'[/bold green] {action} successfully"
|
|
249
249
|
if action == "modified":
|
|
250
|
-
message += "\n[
|
|
250
|
+
message += "\n[bold white]You must re-deploy any agents using this secret set for changes to take effect[/bold white]"
|
|
251
251
|
else:
|
|
252
252
|
message += f"\n[dim]Deploy your agent with {PIPECAT_CLI_NAME} deploy agent-name --secrets {name}[/dim]"
|
|
253
253
|
console.success(message)
|
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
import os
|
|
8
8
|
from typing import Optional
|
|
9
9
|
|
|
10
|
+
import toml
|
|
11
|
+
|
|
10
12
|
from pipecatcloud.cli import PIPECAT_CREDENTIALS_PATH, PIPECAT_DEPLOY_CONFIG_PATH
|
|
11
13
|
from pipecatcloud.config import _SETTINGS, Config, _Setting
|
|
12
14
|
from pipecatcloud.exception import ConfigError
|
|
@@ -26,8 +28,6 @@ deploy_config_path: str = os.environ.get("PIPECAT_DEPLOY_CONFIG_PATH") or os.pat
|
|
|
26
28
|
def _read_user_config():
|
|
27
29
|
config_data = {}
|
|
28
30
|
if os.path.exists(user_config_path):
|
|
29
|
-
import toml
|
|
30
|
-
|
|
31
31
|
try:
|
|
32
32
|
with open(user_config_path) as f:
|
|
33
33
|
config_data = toml.load(f)
|
|
@@ -53,7 +53,8 @@ user_config = _read_user_config()
|
|
|
53
53
|
|
|
54
54
|
|
|
55
55
|
def _write_user_config(new_config):
|
|
56
|
-
|
|
56
|
+
dir_path = os.path.dirname(user_config_path)
|
|
57
|
+
os.makedirs(dir_path, exist_ok=True)
|
|
57
58
|
|
|
58
59
|
with open(user_config_path, "w") as f:
|
|
59
60
|
toml.dump(new_config, f)
|
|
@@ -26,6 +26,7 @@ _SETTINGS = {
|
|
|
26
26
|
"login_status_path": _Setting("/auth/status"),
|
|
27
27
|
"whoami_path": _Setting("/v1/users"),
|
|
28
28
|
"organization_path": _Setting("/v1/organizations"),
|
|
29
|
+
"daily_key_path": _Setting("/v1/organizations/{org}/daily"),
|
|
29
30
|
"services_path": _Setting("/v1/organizations/{org}/services"),
|
|
30
31
|
"services_logs_path": _Setting("/v1/organizations/{org}/services/{service}/logs"),
|
|
31
32
|
"services_deployments_path": _Setting("/v1/organizations/{org}/services/{service}/deployments"),
|
pipecatcloud-0.0.11/CHANGELOG.md
DELETED
|
@@ -1,188 +0,0 @@
|
|
|
1
|
-
# Pipecat Cloud Changelog
|
|
2
|
-
|
|
3
|
-
All notable changes to **Pipecat Cloud** will be documented in this file.
|
|
4
|
-
|
|
5
|
-
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
-
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
-
|
|
8
|
-
## [0.0.11] - 2025-03-04
|
|
9
|
-
|
|
10
|
-
### Changed
|
|
11
|
-
|
|
12
|
-
- `session.py` now returns the response body from the `start()` method.
|
|
13
|
-
|
|
14
|
-
### Fixed
|
|
15
|
-
|
|
16
|
-
- Fixed an issue in `session.py` where a bot wouldn't start due to malformed
|
|
17
|
-
`data`.
|
|
18
|
-
|
|
19
|
-
## [0.0.10] - 2025-03-04
|
|
20
|
-
|
|
21
|
-
### Added
|
|
22
|
-
|
|
23
|
-
- `init` convenience command will now populate the working directory with files
|
|
24
|
-
from the starter project.
|
|
25
|
-
|
|
26
|
-
- `agent log` allows for optional severity level filtering.
|
|
27
|
-
|
|
28
|
-
### Changed
|
|
29
|
-
|
|
30
|
-
- `agent status` and `deploy` no longer show superfluous data.
|
|
31
|
-
|
|
32
|
-
- `session.py` now correctly handles errors when starting agents.
|
|
33
|
-
|
|
34
|
-
- `secrets set` no longer prompts twice for confirmation if the secret set does
|
|
35
|
-
not exist.
|
|
36
|
-
|
|
37
|
-
### Removed
|
|
38
|
-
|
|
39
|
-
- `errors.py` removed as redundant (error message and code returned via API).
|
|
40
|
-
|
|
41
|
-
- `agent_utils.py` removed as redundant (error message and code returned via
|
|
42
|
-
API).
|
|
43
|
-
|
|
44
|
-
## [0.0.9] - 2025-02-27
|
|
45
|
-
|
|
46
|
-
### Added
|
|
47
|
-
|
|
48
|
-
- `agent status [agent-name]` now shows deployment info and scaling
|
|
49
|
-
configuration.
|
|
50
|
-
|
|
51
|
-
- `agent sessions [agent-name]` lists active session count for an agent (will
|
|
52
|
-
list session details in future).
|
|
53
|
-
|
|
54
|
-
- `agent start [agent-name] -D` now shows the Daily room URL (and token) to
|
|
55
|
-
join in the terminal output.
|
|
56
|
-
|
|
57
|
-
### Changed
|
|
58
|
-
|
|
59
|
-
- Changed CLI command from `pipecat` to `pipecatcloud` or `pcc`.
|
|
60
|
-
|
|
61
|
-
- `agent delete` prompts the user for confirmation first.
|
|
62
|
-
|
|
63
|
-
- `agent start` now checks the target deployment first to ensure it exists and
|
|
64
|
-
is in a healthy state.
|
|
65
|
-
|
|
66
|
-
- Changed the information order of `agent status` so the health badge is
|
|
67
|
-
clearly visible in terminal.
|
|
68
|
-
|
|
69
|
-
- `agent deploy` now defaults to "Y" for the confirmation prompts.
|
|
70
|
-
|
|
71
|
-
### Fixed
|
|
72
|
-
|
|
73
|
-
- Fixed lint error with payload data in `agent start`.
|
|
74
|
-
|
|
75
|
-
- Fixed a bug where `pcc-deploy.toml` files were required to be present.
|
|
76
|
-
|
|
77
|
-
- `deploy` command now correctly passes the secret set to the deployment from
|
|
78
|
-
the `pcc-deploy.toml` file.
|
|
79
|
-
|
|
80
|
-
## [0.0.8] - 2025-02-03
|
|
81
|
-
|
|
82
|
-
### Added
|
|
83
|
-
|
|
84
|
-
- `secrets set [set-name] --file` allowing you to create a secret set from .env
|
|
85
|
-
file.
|
|
86
|
-
|
|
87
|
-
- `agent scale` to modify agent configuration without pushing a new image.
|
|
88
|
-
|
|
89
|
-
- `run` command for running bot.py files locally via FastAPI. This initial
|
|
90
|
-
implementation is very basic and will be expanded in the future.
|
|
91
|
-
|
|
92
|
-
- `organizations select` allows passing an `--org / -o` option to bypass
|
|
93
|
-
prompt.
|
|
94
|
-
|
|
95
|
-
### Fixed
|
|
96
|
-
|
|
97
|
-
- All commands use the correct shorthand flag syntax (`-` vs. `--`).
|
|
98
|
-
|
|
99
|
-
- CLI config extends from module config to avoid loading config TOML with
|
|
100
|
-
package imports.
|
|
101
|
-
|
|
102
|
-
- `secrets list` now correctly lists all secrets vs. just a single entry.
|
|
103
|
-
|
|
104
|
-
- `deploy` command displays live status to prevent skewed terminal output.
|
|
105
|
-
|
|
106
|
-
- `deploy` command no longer allows pushing images without a tag.
|
|
107
|
-
|
|
108
|
-
- `agent logs` paginate / filter / sort and tidy up display for logs.
|
|
109
|
-
|
|
110
|
-
- `start` command correctly clears the live terminal text.
|
|
111
|
-
|
|
112
|
-
- `pcc-deploy.toml` files now work as intended with `deploy` command.
|
|
113
|
-
|
|
114
|
-
- `deploy` method now passes configuration parameters correctly.
|
|
115
|
-
|
|
116
|
-
- Switching organizations will fully remove any default API tokens from the
|
|
117
|
-
previously selected organization.
|
|
118
|
-
|
|
119
|
-
### Changed
|
|
120
|
-
|
|
121
|
-
- Local config now retains default keys when switching between organizations.
|
|
122
|
-
|
|
123
|
-
- Local config now retains defaukt keys when logging in again.
|
|
124
|
-
|
|
125
|
-
- `deploy` will check passed secret set exists before deployment.
|
|
126
|
-
|
|
127
|
-
- `secrets list` now takes an optional `--sets / -s` parameter that filters by
|
|
128
|
-
secret sets or image pull secrets.
|
|
129
|
-
|
|
130
|
-
- `organizations keys create` now prompts you to set the newly created key as
|
|
131
|
-
the default after creation (if active org matches).
|
|
132
|
-
|
|
133
|
-
- `organizations keys delete` not prompts to confirm if selected key is
|
|
134
|
-
currently your local config default.
|
|
135
|
-
|
|
136
|
-
- `Agent` module import has been renamed to `Session` to better reflect API.
|
|
137
|
-
|
|
138
|
-
## [0.0.7] - 2025-02-01
|
|
139
|
-
|
|
140
|
-
### Added
|
|
141
|
-
|
|
142
|
-
- `run` command for running an agent locally. This initial implementation is
|
|
143
|
-
very basic and will be expanded in the future.
|
|
144
|
-
|
|
145
|
-
### Changed
|
|
146
|
-
|
|
147
|
-
- `start_agent` method no longer requires an organization. If not provided, it
|
|
148
|
-
will assume the namespace of the API token owner.
|
|
149
|
-
|
|
150
|
-
- `start` command no longer looks up the agent before starting (health check is
|
|
151
|
-
handled by the proxy route).
|
|
152
|
-
|
|
153
|
-
## [0.0.6] - 2025-02-01
|
|
154
|
-
|
|
155
|
-
### Added
|
|
156
|
-
|
|
157
|
-
- `pipecatcloud.agent` module for working with agents via Python scripts.
|
|
158
|
-
|
|
159
|
-
- `start_agent` method for starting an agent.
|
|
160
|
-
|
|
161
|
-
### Backlog
|
|
162
|
-
|
|
163
|
-
- `deploy` make image pull secrets non-optional, but allow for bypassing.
|
|
164
|
-
|
|
165
|
-
- Fix: update docs to assert that the bot method must be async.
|
|
166
|
-
|
|
167
|
-
- Fix: Secrets are not upserting (overriding each time, which may be.
|
|
168
|
-
preferable?).
|
|
169
|
-
|
|
170
|
-
- Fix: deployment process needs better output.
|
|
171
|
-
|
|
172
|
-
- `organizations keys create` should ask if you'd like to set the created key
|
|
173
|
-
as default after creation (if org matches).
|
|
174
|
-
|
|
175
|
-
- Sense check image parameter of the deploy command (does it have a tag, etc).
|
|
176
|
-
|
|
177
|
-
- `agent logs` paginate / filter / sort and tidy up display for logs.
|
|
178
|
-
|
|
179
|
-
- Fix: start command should clear the live text.
|
|
180
|
-
|
|
181
|
-
- Secrets from .env method.
|
|
182
|
-
|
|
183
|
-
- Fix: .pcc-deploy.toml should read correctly.
|
|
184
|
-
|
|
185
|
-
- New convenience method to add account associated Daily API Key to a secret
|
|
186
|
-
set.
|
|
187
|
-
|
|
188
|
-
- Add: concurrency support for agent deployments.
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
name: Publish to PyPI
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
workflow_dispatch:
|
|
5
|
-
inputs:
|
|
6
|
-
version:
|
|
7
|
-
description: 'Version to publish (must match pyproject.toml, e.g. 0.0.4)'
|
|
8
|
-
required: true
|
|
9
|
-
type: string
|
|
10
|
-
|
|
11
|
-
jobs:
|
|
12
|
-
build-and-publish:
|
|
13
|
-
runs-on: ubuntu-latest
|
|
14
|
-
environment:
|
|
15
|
-
name: pypi
|
|
16
|
-
url: https://pypi.org/p/pipecat-cloud
|
|
17
|
-
permissions:
|
|
18
|
-
id-token: write # IMPORTANT: this permission is needed for trusted publishing
|
|
19
|
-
contents: write # Needed for tagging
|
|
20
|
-
|
|
21
|
-
steps:
|
|
22
|
-
- name: Checkout code
|
|
23
|
-
uses: actions/checkout@v4
|
|
24
|
-
|
|
25
|
-
- name: Set up Python
|
|
26
|
-
uses: actions/setup-python@v4
|
|
27
|
-
with:
|
|
28
|
-
python-version: '3.10'
|
|
29
|
-
|
|
30
|
-
- name: Verify version matches
|
|
31
|
-
run: |
|
|
32
|
-
pip install tomli
|
|
33
|
-
PROJECT_VERSION=$(python -c "import tomli; print(tomli.load(open('pyproject.toml', 'rb'))['project']['version'])")
|
|
34
|
-
if [ "$PROJECT_VERSION" != "${{ github.event.inputs.version }}" ]; then
|
|
35
|
-
echo "Error: Input version (${{ github.event.inputs.version }}) does not match pyproject.toml version ($PROJECT_VERSION)"
|
|
36
|
-
exit 1
|
|
37
|
-
fi
|
|
38
|
-
|
|
39
|
-
- name: Install dependencies
|
|
40
|
-
run: |
|
|
41
|
-
python -m pip install --upgrade pip
|
|
42
|
-
pip install -r requirements.txt
|
|
43
|
-
pip install build twine
|
|
44
|
-
|
|
45
|
-
- name: Build package
|
|
46
|
-
run: python -m build
|
|
47
|
-
|
|
48
|
-
- name: Create release tag
|
|
49
|
-
run: |
|
|
50
|
-
git config --local user.email "action@github.com"
|
|
51
|
-
git config --local user.name "GitHub Action"
|
|
52
|
-
git tag -a "v${{ github.event.inputs.version }}" -m "Version ${{ github.event.inputs.version }}"
|
|
53
|
-
git push origin "v${{ github.event.inputs.version }}"
|
|
54
|
-
|
|
55
|
-
- name: Publish to PyPI
|
|
56
|
-
uses: pypa/gh-action-pypi-publish@release/v1
|
|
57
|
-
with:
|
|
58
|
-
verbose: true
|
|
59
|
-
print-hash: true
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
name: Publish to TEST PyPI
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
workflow_dispatch:
|
|
5
|
-
inputs:
|
|
6
|
-
version:
|
|
7
|
-
description: 'Version to publish (must match pyproject.toml, e.g. 0.0.4)'
|
|
8
|
-
required: true
|
|
9
|
-
type: string
|
|
10
|
-
|
|
11
|
-
jobs:
|
|
12
|
-
build-and-publish:
|
|
13
|
-
runs-on: ubuntu-latest
|
|
14
|
-
environment:
|
|
15
|
-
name: pypi
|
|
16
|
-
url: https://test.pypi.org/project/pipecat-cloud
|
|
17
|
-
permissions:
|
|
18
|
-
id-token: write # IMPORTANT: this permission is needed for trusted publishing
|
|
19
|
-
contents: write # Needed for tagging
|
|
20
|
-
|
|
21
|
-
steps:
|
|
22
|
-
- name: Checkout code
|
|
23
|
-
uses: actions/checkout@v4
|
|
24
|
-
|
|
25
|
-
- name: Set up Python
|
|
26
|
-
uses: actions/setup-python@v4
|
|
27
|
-
with:
|
|
28
|
-
python-version: '3.10'
|
|
29
|
-
|
|
30
|
-
- name: Verify version matches
|
|
31
|
-
run: |
|
|
32
|
-
pip install tomli
|
|
33
|
-
PROJECT_VERSION=$(python -c "import tomli; print(tomli.load(open('pyproject.toml', 'rb'))['project']['version'])")
|
|
34
|
-
if [ "$PROJECT_VERSION" != "${{ github.event.inputs.version }}" ]; then
|
|
35
|
-
echo "Error: Input version (${{ github.event.inputs.version }}) does not match pyproject.toml version ($PROJECT_VERSION)"
|
|
36
|
-
exit 1
|
|
37
|
-
fi
|
|
38
|
-
|
|
39
|
-
- name: Install dependencies
|
|
40
|
-
run: |
|
|
41
|
-
python -m pip install --upgrade pip
|
|
42
|
-
pip install -r requirements.txt
|
|
43
|
-
pip install build twine
|
|
44
|
-
|
|
45
|
-
- name: Build package
|
|
46
|
-
run: python -m build
|
|
47
|
-
|
|
48
|
-
- name: Create release tag
|
|
49
|
-
run: |
|
|
50
|
-
git config --local user.email "action@github.com"
|
|
51
|
-
git config --local user.name "GitHub Action"
|
|
52
|
-
git tag -a "v${{ github.event.inputs.version }}" -m "Version ${{ github.event.inputs.version }}"
|
|
53
|
-
git push origin "v${{ github.event.inputs.version }}"
|
|
54
|
-
|
|
55
|
-
- name: Publish to PyPI
|
|
56
|
-
uses: pypa/gh-action-pypi-publish@release/v1
|
|
57
|
-
with:
|
|
58
|
-
verbose: true
|
|
59
|
-
print-hash: true
|
|
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
|