pipecatcloud 0.1.0__tar.gz → 0.1.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.
Files changed (44) hide show
  1. {pipecatcloud-0.1.0 → pipecatcloud-0.1.2}/.github/workflows/publish-pypi.yml +10 -3
  2. {pipecatcloud-0.1.0 → pipecatcloud-0.1.2}/.github/workflows/publish-test.yml +14 -6
  3. {pipecatcloud-0.1.0 → pipecatcloud-0.1.2}/CHANGELOG.md +25 -3
  4. {pipecatcloud-0.1.0/src/pipecatcloud.egg-info → pipecatcloud-0.1.2}/PKG-INFO +2 -2
  5. {pipecatcloud-0.1.0 → pipecatcloud-0.1.2}/README.md +1 -1
  6. {pipecatcloud-0.1.0 → pipecatcloud-0.1.2}/pyproject.toml +1 -1
  7. {pipecatcloud-0.1.0 → pipecatcloud-0.1.2}/src/pipecatcloud/__init__.py +7 -2
  8. pipecatcloud-0.1.2/src/pipecatcloud/agent.py +52 -0
  9. {pipecatcloud-0.1.0 → pipecatcloud-0.1.2}/src/pipecatcloud/cli/commands/agent.py +17 -7
  10. {pipecatcloud-0.1.0 → pipecatcloud-0.1.2}/src/pipecatcloud/cli/commands/deploy.py +51 -18
  11. {pipecatcloud-0.1.0 → pipecatcloud-0.1.2}/src/pipecatcloud/cli/config.py +18 -8
  12. {pipecatcloud-0.1.0 → pipecatcloud-0.1.2}/src/pipecatcloud/exception.py +7 -1
  13. {pipecatcloud-0.1.0 → pipecatcloud-0.1.2/src/pipecatcloud.egg-info}/PKG-INFO +2 -2
  14. {pipecatcloud-0.1.0 → pipecatcloud-0.1.2}/src/pipecatcloud.egg-info/SOURCES.txt +1 -0
  15. {pipecatcloud-0.1.0 → pipecatcloud-0.1.2}/.github/workflows/python-publish.yml +0 -0
  16. {pipecatcloud-0.1.0 → pipecatcloud-0.1.2}/.gitignore +0 -0
  17. {pipecatcloud-0.1.0 → pipecatcloud-0.1.2}/LICENSE +0 -0
  18. {pipecatcloud-0.1.0 → pipecatcloud-0.1.2}/dev-requirements.txt +0 -0
  19. {pipecatcloud-0.1.0 → pipecatcloud-0.1.2}/pipecat-cloud.png +0 -0
  20. {pipecatcloud-0.1.0 → pipecatcloud-0.1.2}/setup.cfg +0 -0
  21. {pipecatcloud-0.1.0 → pipecatcloud-0.1.2}/src/pipecatcloud/__main__.py +0 -0
  22. {pipecatcloud-0.1.0 → pipecatcloud-0.1.2}/src/pipecatcloud/__version__.py +0 -0
  23. {pipecatcloud-0.1.0 → pipecatcloud-0.1.2}/src/pipecatcloud/_utils/__init__.py +0 -0
  24. {pipecatcloud-0.1.0 → pipecatcloud-0.1.2}/src/pipecatcloud/_utils/async_utils.py +0 -0
  25. {pipecatcloud-0.1.0 → pipecatcloud-0.1.2}/src/pipecatcloud/_utils/auth_utils.py +0 -0
  26. {pipecatcloud-0.1.0 → pipecatcloud-0.1.2}/src/pipecatcloud/_utils/console_utils.py +0 -0
  27. {pipecatcloud-0.1.0 → pipecatcloud-0.1.2}/src/pipecatcloud/_utils/deploy_utils.py +0 -0
  28. {pipecatcloud-0.1.0 → pipecatcloud-0.1.2}/src/pipecatcloud/_utils/local_runner.py +0 -0
  29. {pipecatcloud-0.1.0 → pipecatcloud-0.1.2}/src/pipecatcloud/api.py +0 -0
  30. {pipecatcloud-0.1.0 → pipecatcloud-0.1.2}/src/pipecatcloud/cli/__init__.py +0 -0
  31. {pipecatcloud-0.1.0 → pipecatcloud-0.1.2}/src/pipecatcloud/cli/api.py +0 -0
  32. {pipecatcloud-0.1.0 → pipecatcloud-0.1.2}/src/pipecatcloud/cli/commands/__init__.py +0 -0
  33. {pipecatcloud-0.1.0 → pipecatcloud-0.1.2}/src/pipecatcloud/cli/commands/auth.py +0 -0
  34. {pipecatcloud-0.1.0 → pipecatcloud-0.1.2}/src/pipecatcloud/cli/commands/init.py +0 -0
  35. {pipecatcloud-0.1.0 → pipecatcloud-0.1.2}/src/pipecatcloud/cli/commands/organizations.py +0 -0
  36. {pipecatcloud-0.1.0 → pipecatcloud-0.1.2}/src/pipecatcloud/cli/commands/run.py +0 -0
  37. {pipecatcloud-0.1.0 → pipecatcloud-0.1.2}/src/pipecatcloud/cli/commands/secrets.py +0 -0
  38. {pipecatcloud-0.1.0 → pipecatcloud-0.1.2}/src/pipecatcloud/cli/entry_point.py +0 -0
  39. {pipecatcloud-0.1.0 → pipecatcloud-0.1.2}/src/pipecatcloud/config.py +0 -0
  40. {pipecatcloud-0.1.0 → pipecatcloud-0.1.2}/src/pipecatcloud/session.py +0 -0
  41. {pipecatcloud-0.1.0 → pipecatcloud-0.1.2}/src/pipecatcloud.egg-info/dependency_links.txt +0 -0
  42. {pipecatcloud-0.1.0 → pipecatcloud-0.1.2}/src/pipecatcloud.egg-info/entry_points.txt +0 -0
  43. {pipecatcloud-0.1.0 → pipecatcloud-0.1.2}/src/pipecatcloud.egg-info/requires.txt +0 -0
  44. {pipecatcloud-0.1.0 → pipecatcloud-0.1.2}/src/pipecatcloud.egg-info/top_level.txt +0 -0
@@ -45,12 +45,19 @@ jobs:
45
45
  - name: Build package
46
46
  run: python -m build
47
47
 
48
- - name: Create release tag
48
+ - name: Check and create release tag if needed
49
49
  run: |
50
50
  git config --local user.email "action@github.com"
51
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 }}"
52
+
53
+ # Check if tag already exists remotely
54
+ if git ls-remote --tags origin | grep -q "refs/tags/v${{ github.event.inputs.version }}"; then
55
+ echo "Tag v${{ github.event.inputs.version }} already exists, skipping tag creation"
56
+ else
57
+ echo "Creating new tag v${{ github.event.inputs.version }}"
58
+ git tag -a "v${{ github.event.inputs.version }}" -m "Version ${{ github.event.inputs.version }}"
59
+ git push origin "v${{ github.event.inputs.version }}"
60
+ fi
54
61
 
55
62
  - name: Publish to PyPI
56
63
  uses: pypa/gh-action-pypi-publish@release/v1
@@ -15,8 +15,8 @@ jobs:
15
15
  name: pypi
16
16
  url: https://test.pypi.org/project/pipecat-cloud
17
17
  permissions:
18
- id-token: write # IMPORTANT: this permission is needed for trusted publishing
19
- contents: write # Needed for tagging
18
+ id-token: write
19
+ contents: write
20
20
 
21
21
  steps:
22
22
  - name: Checkout code
@@ -45,15 +45,23 @@ jobs:
45
45
  - name: Build package
46
46
  run: python -m build
47
47
 
48
- - name: Create release tag
48
+ - name: Check and create release tag if needed
49
49
  run: |
50
50
  git config --local user.email "action@github.com"
51
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 }}"
52
+
53
+ # Check if tag already exists remotely
54
+ if git ls-remote --tags origin | grep -q "refs/tags/v${{ github.event.inputs.version }}"; then
55
+ echo "Tag v${{ github.event.inputs.version }} already exists, skipping tag creation"
56
+ else
57
+ echo "Creating new tag v${{ github.event.inputs.version }}"
58
+ git tag -a "v${{ github.event.inputs.version }}" -m "Version ${{ github.event.inputs.version }}"
59
+ git push origin "v${{ github.event.inputs.version }}"
60
+ fi
54
61
 
55
62
  - name: Publish to PyPI
56
63
  uses: pypa/gh-action-pypi-publish@release/v1
57
64
  with:
65
+ repository-url: https://test.pypi.org/legacy/
58
66
  verbose: true
59
- print-hash: true
67
+ print-hash: true
@@ -5,13 +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
+ ## [Unreleased]
9
+
10
+ ## [0.1.2] - 2025-03-12
11
+
12
+ ### Added
13
+
14
+ - `agent.py` data classes for use in base images, providing guidance on params
15
+
16
+ ### Fixed
17
+
18
+ - Lookup issue when passing an image pull secret to the `deploy` command
19
+
20
+ ### Changed
21
+
22
+ - Change the of deploy checks from 30 to 18, reducing the overall time for a
23
+ deployment.
24
+
25
+ - Added a `--format / -f` option for `agent logs`. Options are `TEXT` and
26
+ `JSON`.
27
+
28
+ - Improved error messaging for `ConfigError` to improve debugging.
29
+
8
30
  ## [0.1.0] - 2025-03-05
9
31
 
10
- - `pipecatcloud.toml` moved to `$HOME/.config/pipecatcloud/pipecatcloud.toml`
32
+ - `pipecatcloud.toml` moved to `$HOME/.config/pipecatcloud/pipecatcloud.toml`.
11
33
 
12
34
  ### Added
13
35
 
14
- - `pcc auth whoami` now shows the namespace Daily API key for convenience
36
+ - `pcc auth whoami` now shows the namespace Daily API key for convenience.
15
37
 
16
38
  ## [0.0.11] - 2025-03-04
17
39
 
@@ -83,4 +105,4 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
83
105
  - Fixed a bug where `pcc-deploy.toml` files were required to be present.
84
106
 
85
107
  - `deploy` command now correctly passes the secret set to the deployment from
86
- the `pcc-deploy.toml` file.
108
+ the `pcc-deploy.toml` file.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: pipecatcloud
3
- Version: 0.1.0
3
+ Version: 0.1.2
4
4
  Summary: Cloud hosting for Pipecat AI applications
5
5
  License: BSD 2-Clause License
6
6
  Project-URL: Website, https://docs.pipecat.daily.co/
@@ -19,7 +19,7 @@ Requires-Dist: toml~=0.10.2
19
19
  Requires-Dist: questionary~=2.1.0
20
20
 
21
21
  <h1><div align="center">
22
- <img alt="pipecat cloud" width="500px" height="auto" src="./pipecat-cloud.png">
22
+ <img alt="pipecat cloud" width="500px" height="auto" src="https://raw.githubusercontent.com/daily-co/pipecat-cloud/main/pipecat-cloud.png">
23
23
  </div></h1>
24
24
 
25
25
  [![Docs](https://img.shields.io/badge/documentation-blue)](https://docs.pipecat.daily.co)
@@ -1,5 +1,5 @@
1
1
  <h1><div align="center">
2
- <img alt="pipecat cloud" width="500px" height="auto" src="./pipecat-cloud.png">
2
+ <img alt="pipecat cloud" width="500px" height="auto" src="https://raw.githubusercontent.com/daily-co/pipecat-cloud/main/pipecat-cloud.png">
3
3
  </div></h1>
4
4
 
5
5
  [![Docs](https://img.shields.io/badge/documentation-blue)](https://docs.pipecat.daily.co)
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "pipecatcloud"
7
- version = "0.1.0"
7
+ version = "0.1.2"
8
8
  requires-python = ">=3.10"
9
9
  description = "Cloud hosting for Pipecat AI applications"
10
10
  license = { text = "BSD 2-Clause License" }
@@ -9,7 +9,8 @@ import sys
9
9
 
10
10
  from loguru import logger
11
11
 
12
- from .exception import (
12
+ from pipecatcloud.agent import DailySessionArguments, SessionArguments, WebSocketSessionArguments
13
+ from pipecatcloud.exception import (
13
14
  AgentNotHealthyError,
14
15
  AgentStartError,
15
16
  AuthError,
@@ -18,13 +19,17 @@ from .exception import (
18
19
  Error,
19
20
  InvalidError,
20
21
  )
21
- from .session import Session, SessionParams
22
+ from pipecatcloud.session import Session, SessionParams
22
23
 
23
24
  logger.remove()
24
25
  logger.add(sys.stderr, level=str(os.getenv("PCC_LOG_LEVEL", "INFO")))
25
26
 
26
27
 
27
28
  __all__ = [
29
+ # Agent classes
30
+ "SessionArguments",
31
+ "DailySessionArguments",
32
+ "WebSocketSessionArguments",
28
33
  # Session classes
29
34
  "Session",
30
35
  "SessionParams",
@@ -0,0 +1,52 @@
1
+ #
2
+ # Copyright (c) 2025, Daily
3
+ #
4
+ # SPDX-License-Identifier: BSD 2-Clause License
5
+ #
6
+
7
+ from dataclasses import dataclass
8
+ from typing import Any, Optional
9
+
10
+ from fastapi import WebSocket
11
+
12
+
13
+ @dataclass
14
+ class SessionArguments:
15
+ """Base class for common agent session arguments. The arguments are received
16
+ by the bot() entry point.
17
+
18
+ """
19
+
20
+ session_id: Optional[str]
21
+
22
+
23
+ @dataclass
24
+ class PipecatSessionArguments(SessionArguments):
25
+ """Standard Pipecat Cloud agent session arguments. The arguments are
26
+ received by the bot() entry point.
27
+
28
+ """
29
+
30
+ body: Any
31
+
32
+
33
+ @dataclass
34
+ class DailySessionArguments(SessionArguments):
35
+ """Daily based agent session arguments. The arguments are received by the
36
+ bot() entry point.
37
+
38
+ """
39
+
40
+ room_url: str
41
+ token: str
42
+ body: Any
43
+
44
+
45
+ @dataclass
46
+ class WebSocketSessionArguments(SessionArguments):
47
+ """Websocket based agent session arguments. The arguments are received by
48
+ the bot() entry point.
49
+
50
+ """
51
+
52
+ websocket: WebSocket
@@ -4,6 +4,7 @@
4
4
  # SPDX-License-Identifier: BSD 2-Clause License
5
5
  #
6
6
 
7
+ import json
7
8
  from enum import Enum
8
9
 
9
10
  import aiohttp
@@ -220,6 +221,11 @@ async def scale():
220
221
  console.error("Not implemented")
221
222
 
222
223
 
224
+ class LogFormat(str, Enum):
225
+ TEXT = "TEXT"
226
+ JSON = "JSON"
227
+
228
+
223
229
  class LogLevel(str, Enum):
224
230
  DEBUG = "DEBUG"
225
231
  INFO = "INFO"
@@ -229,8 +235,8 @@ class LogLevel(str, Enum):
229
235
 
230
236
 
231
237
  class LogLevelColors(str, Enum):
232
- DEBUG = "dim white"
233
- INFO = "white"
238
+ DEBUG = "blue"
239
+ INFO = "green"
234
240
  WARNING = "yellow"
235
241
  ERROR = "red"
236
242
  CRITICAL = "bold red"
@@ -245,6 +251,7 @@ async def logs(
245
251
  None, "--organization", "-o", help="Organization to get status of agent for"
246
252
  ),
247
253
  level: LogLevel = typer.Option(None, "--level", "-l", help="Level of logs to get"),
254
+ format: LogFormat = typer.Option(LogFormat.TEXT, "--format", "-f", help="Logs format"),
248
255
  limit: int = typer.Option(100, "--limit", "-n", help="Number of logs to get"),
249
256
  ):
250
257
  org = organization or config.get("org")
@@ -271,10 +278,14 @@ async def logs(
271
278
  # filter out any messages that do not match our log level
272
279
  if level and severity.value != level.value:
273
280
  continue
274
- color = getattr(LogLevelColors, severity, LogLevelColors.DEBUG).value
275
- console.print(Text(timestamp, style="bold dim"))
276
- console.print(Text(l.get("log", ""), style=color))
277
- console.rule(style="dim")
281
+
282
+ if format == LogFormat.TEXT:
283
+ color = getattr(LogLevelColors, severity, LogLevelColors.DEBUG).value
284
+ console.print(Text(timestamp, style="bold dim"), end=" ")
285
+ console.print(Text(l.get("log", ""), style=color))
286
+ elif format == LogFormat.JSON:
287
+ line = {"timestamp": timestamp, "log": l.get("log", "")}
288
+ console.print(Text(json.dumps(line, ensure_ascii=False), style="gray"))
278
289
 
279
290
 
280
291
  @agent_cli.command(name="delete", help="Delete an agent.")
@@ -349,7 +360,6 @@ async def deployments(
349
360
  response.raise_for_status()
350
361
 
351
362
  data = await response.json()
352
- print(data)
353
363
 
354
364
  table = Table(
355
365
  show_header=True,
@@ -25,7 +25,7 @@ from pipecatcloud.cli import PIPECAT_CLI_NAME
25
25
  from pipecatcloud.cli.api import API
26
26
  from pipecatcloud.cli.config import config
27
27
 
28
- MAX_ALIVE_CHECKS = 30
28
+ MAX_ALIVE_CHECKS = 18
29
29
  ALIVE_CHECK_SLEEP = 5
30
30
 
31
31
  # ----- Command
@@ -36,7 +36,8 @@ async def _deploy(params: DeployConfigParams, org, force: bool = False):
36
36
 
37
37
  # Check for an existing deployment with this agent name
38
38
  with Live(
39
- console.status("[dim]Checking for existing agent deployment...[/dim]", spinner="dots"), transient=True
39
+ console.status("[dim]Checking for existing agent deployment...[/dim]", spinner="dots"),
40
+ transient=True,
40
41
  ) as live:
41
42
  data, error = await API.agent(agent_name=params.agent_name, org=org, live=live)
42
43
 
@@ -57,7 +58,7 @@ async def _deploy(params: DeployConfigParams, org, force: bool = False):
57
58
  return typer.Exit()
58
59
 
59
60
  # Start the deployment process
60
- with Live(console.status("[dim]Preparing deployment...", spinner="dots")) as live:
61
+ with Live(console.status("[dim]Preparing deployment...", spinner="dots"), transient=True) as live:
61
62
  """
62
63
  # 1. Check that provided secret set exists
63
64
  """
@@ -93,7 +94,7 @@ async def _deploy(params: DeployConfigParams, org, force: bool = False):
93
94
  )
94
95
 
95
96
  if error:
96
- if error == 400:
97
+ if error.get("code") == "400":
97
98
  creds_exist = True
98
99
  else:
99
100
  API.print_error()
@@ -134,9 +135,13 @@ async def _deploy(params: DeployConfigParams, org, force: bool = False):
134
135
  is_ready = False
135
136
  checks_performed = 0
136
137
 
138
+ console.print(
139
+ f"[bold cyan]{'Updating' if existing_agent else 'Pushing'}[/bold cyan] deployment for agent '{params.agent_name}'")
140
+
137
141
  # Create a simple spinner for the polling phase
142
+ deployment_status_message = "[dim]Waiting for deployment to become ready...[/dim]"
138
143
  with console.status(
139
- "[dim]Waiting for deployment to become ready...[/dim]", spinner="bouncingBar"
144
+ deployment_status_message, spinner="bouncingBar"
140
145
  ) as status:
141
146
  try:
142
147
  while checks_performed < MAX_ALIVE_CHECKS:
@@ -153,6 +158,7 @@ async def _deploy(params: DeployConfigParams, org, force: bool = False):
153
158
  # Update deployment ID if received (silently)
154
159
  if not active_deployment_id and agent_status.get("activeDeploymentId"):
155
160
  active_deployment_id = agent_status["activeDeploymentId"]
161
+ deployment_status_message = f"[dim]Waiting for deployment to become ready (deployment ID: {active_deployment_id})...[/dim]"
156
162
 
157
163
  # Check if deployment is ready
158
164
  if agent_status.get("ready"):
@@ -176,17 +182,37 @@ async def _deploy(params: DeployConfigParams, org, force: bool = False):
176
182
  console.error("Deployment failed with the above error")
177
183
  return typer.Exit()
178
184
 
185
+ # check for org secret
186
+ default_public_api_key = config.get("default_public_key")
187
+
179
188
  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
- )
189
+ if not default_public_api_key:
190
+ console.print(
191
+ Panel(
192
+ f"No public API key provided. Please provide a public API key using the --api-key flag or set a default using [bold cyan]{PIPECAT_CLI_NAME} organizations keys use[/bold cyan].\n\n"
193
+ f"If you have not yet created a public API key, you can do so by running [bold cyan]{PIPECAT_CLI_NAME} organizations keys create[/bold cyan].\n\n"
194
+ f"Then...\n\n"
195
+ f"[dim]Start a session with your new agent by running:\n[/dim]"
196
+ f"[bold]`{PIPECAT_CLI_NAME} agent start {params.agent_name}`[/bold]",
197
+ title="Public API Key Required",
198
+ title_align="left",
199
+ border_style="yellow",
200
+ )
201
+ )
202
+
203
+ return typer.Exit(1)
204
+ else:
205
+ console.success(
206
+ f"Agent deployment [bold]'{params.agent_name}'[/bold] is ready\n\n"
207
+ f"[dim]Start a session with your new agent by running:\n[/dim]"
208
+ f"[bold]`{PIPECAT_CLI_NAME} agent start {params.agent_name}`[/bold]",
209
+ title_extra=f"{'Update' if existing_agent else 'Deployment'} complete",
210
+ )
186
211
  else:
187
212
  console.error(
188
213
  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}`")
214
+ f"Please check logs with `{PIPECAT_CLI_NAME} agent logs {params.agent_name}`"
215
+ )
190
216
 
191
217
  return typer.Exit()
192
218
 
@@ -299,17 +325,24 @@ def create_deploy_command(app: typer.Typer):
299
325
  (f"[bold white]Agent name:[/bold white] [green]{partial_config.agent_name}[/green]"),
300
326
  (f"[bold white]Image:[/bold white] [green]{partial_config.image}[/green]"),
301
327
  (f"[bold white]Organization:[/bold white] [green]{org}[/green]"),
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]'}"),
328
+ (
329
+ f"[bold white]Secret set:[/bold white] {'[dim]None[/dim]' if not partial_config.secret_set else '[green] '+ partial_config.secret_set + '[/green]'}"
330
+ ),
331
+ (
332
+ f"[bold white]Image pull secret:[/bold white] {'[dim]None[/dim]' if not partial_config.image_credentials else '[green]' + partial_config.image_credentials + '[/green]'}"
333
+ ),
304
334
  "\n[dim]Scaling configuration:[/dim]",
305
335
  table,
306
- *
307
- (
308
- [] if partial_config.scaling.min_instances else [
336
+ *(
337
+ []
338
+ if partial_config.scaling.min_instances
339
+ else [
309
340
  Text(
310
341
  "Note: Deploying with 0 minimum instances may result in cold starts",
311
342
  style="red",
312
- )]),
343
+ )
344
+ ]
345
+ ),
313
346
  )
314
347
 
315
348
  console.print(
@@ -27,22 +27,26 @@ deploy_config_path: str = os.environ.get("PIPECAT_DEPLOY_CONFIG_PATH") or os.pat
27
27
 
28
28
  def _read_user_config():
29
29
  config_data = {}
30
+ config_problem = ""
31
+
30
32
  if os.path.exists(user_config_path):
31
33
  try:
32
34
  with open(user_config_path) as f:
33
35
  config_data = toml.load(f)
36
+ except toml.TomlDecodeError as exc:
37
+ config_problem = f"Invalid TOML syntax in config file: {exc}"
38
+ except PermissionError:
39
+ config_problem = f"Permission denied when reading config file: {user_config_path}"
40
+ except IOError as exc:
41
+ config_problem = f"I/O error when reading config file: {exc}"
34
42
  except Exception as exc:
35
- config_problem = str(exc)
43
+ config_problem = f"Error reading config file: {exc}"
36
44
  else:
37
45
  top_level_keys = {"token", "org"}
38
46
  org_sections = {k: v for k, v in config_data.items() if k not in top_level_keys}
39
47
 
40
48
  if not all(isinstance(e, dict) for e in org_sections.values()):
41
- raise ConfigError(
42
- "Pipecat Cloud config file is not valid TOML. Organization sections must be dictionaries. Please log out and log back in."
43
- )
44
- else:
45
- config_problem = ""
49
+ config_problem = "Pipecat Cloud config file is not valid TOML. Organization sections must be dictionaries. Please log out and log back in."
46
50
  if config_problem:
47
51
  raise ConfigError(config_problem)
48
52
 
@@ -87,8 +91,14 @@ def update_user_config(
87
91
 
88
92
  try:
89
93
  _write_user_config(existing_config)
90
- except Exception:
91
- raise ConfigError
94
+ except PermissionError:
95
+ raise ConfigError(f"Permission denied when writing to {user_config_path}")
96
+ except FileNotFoundError:
97
+ raise ConfigError(f"Cannot create configuration directory for {user_config_path}")
98
+ except IOError as e:
99
+ raise ConfigError(f"IO error when writing configuration: {str(e)}")
100
+ except Exception as e:
101
+ raise ConfigError(f"Unexpected error updating configuration: {str(e)}")
92
102
 
93
103
 
94
104
  # --- Config
@@ -6,6 +6,8 @@
6
6
 
7
7
  from typing import Optional, Union
8
8
 
9
+ from pipecatcloud.cli import PIPECAT_CLI_NAME
10
+
9
11
 
10
12
  class Error(Exception):
11
13
  """Base class for exceptions in this module."""
@@ -24,7 +26,7 @@ class AuthError(Error):
24
26
 
25
27
  def __init__(
26
28
  self,
27
- message: str = "Unauthorized / token expired. Please run `pcc auth login` to login again.",
29
+ message: str = f"Unauthorized / token expired. Please run `{PIPECAT_CLI_NAME} auth login` to login again.",
28
30
  ):
29
31
  self.message = message
30
32
  super().__init__(self.message)
@@ -37,6 +39,10 @@ class InvalidError(Error):
37
39
  class ConfigError(Error):
38
40
  """Raised when config is unable to be stored or updated"""
39
41
 
42
+ def __init__(self, message: str = "Failed to update configuration"):
43
+ self.message = message
44
+ super().__init__(self.message)
45
+
40
46
 
41
47
  class AgentNotHealthyError(Error):
42
48
  """Raised when agent is not healthy and cannot be started."""
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: pipecatcloud
3
- Version: 0.1.0
3
+ Version: 0.1.2
4
4
  Summary: Cloud hosting for Pipecat AI applications
5
5
  License: BSD 2-Clause License
6
6
  Project-URL: Website, https://docs.pipecat.daily.co/
@@ -19,7 +19,7 @@ Requires-Dist: toml~=0.10.2
19
19
  Requires-Dist: questionary~=2.1.0
20
20
 
21
21
  <h1><div align="center">
22
- <img alt="pipecat cloud" width="500px" height="auto" src="./pipecat-cloud.png">
22
+ <img alt="pipecat cloud" width="500px" height="auto" src="https://raw.githubusercontent.com/daily-co/pipecat-cloud/main/pipecat-cloud.png">
23
23
  </div></h1>
24
24
 
25
25
  [![Docs](https://img.shields.io/badge/documentation-blue)](https://docs.pipecat.daily.co)
@@ -11,6 +11,7 @@ pyproject.toml
11
11
  src/pipecatcloud/__init__.py
12
12
  src/pipecatcloud/__main__.py
13
13
  src/pipecatcloud/__version__.py
14
+ src/pipecatcloud/agent.py
14
15
  src/pipecatcloud/api.py
15
16
  src/pipecatcloud/config.py
16
17
  src/pipecatcloud/exception.py
File without changes
File without changes
File without changes