tavus-cli 0.3.2__tar.gz → 0.3.4__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 (106) hide show
  1. {tavus_cli-0.3.2 → tavus_cli-0.3.4}/.env.example +7 -0
  2. {tavus_cli-0.3.2 → tavus_cli-0.3.4}/.github/workflows/ci.yml +22 -0
  3. tavus_cli-0.3.4/.github/workflows/deploy-cloudflare-worker.yml +102 -0
  4. {tavus_cli-0.3.2 → tavus_cli-0.3.4}/.github/workflows/pr-reviews.yml +1 -1
  5. tavus_cli-0.3.4/.github/workflows/pypi-cli.yml +333 -0
  6. tavus_cli-0.3.4/.github/workflows/tail-cloudflare-worker.yml +52 -0
  7. tavus_cli-0.3.4/.github/workflows/validate-staging-deployment.yml +87 -0
  8. tavus_cli-0.3.4/.release-please-manifest.json +3 -0
  9. tavus_cli-0.3.4/AGENTS.md +37 -0
  10. tavus_cli-0.3.4/CHANGELOG.md +25 -0
  11. tavus_cli-0.3.4/PKG-INFO +330 -0
  12. tavus_cli-0.3.4/README.md +308 -0
  13. {tavus_cli-0.3.2 → tavus_cli-0.3.4}/docs/gemini-enterprise/README.md +50 -54
  14. {tavus_cli-0.3.2 → tavus_cli-0.3.4}/docs/gemini-enterprise/listing.md +4 -5
  15. {tavus_cli-0.3.2 → tavus_cli-0.3.4}/docs/gemini-enterprise/test-queries.md +12 -12
  16. {tavus_cli-0.3.2 → tavus_cli-0.3.4}/docs/usage-observability.md +1 -1
  17. {tavus_cli-0.3.2 → tavus_cli-0.3.4}/pyproject.toml +6 -1
  18. tavus_cli-0.3.4/release-please-config.json +49 -0
  19. tavus_cli-0.3.4/scripts/__init__.py +1 -0
  20. tavus_cli-0.3.4/scripts/check_release_versions.py +90 -0
  21. {tavus_cli-0.3.2 → tavus_cli-0.3.4}/skills/tavus-agentic-pals/SKILL.md +90 -35
  22. tavus_cli-0.3.4/skills/tavus-agentic-pals/references/build-and-verify.md +85 -0
  23. tavus_cli-0.3.4/skills/tavus-agentic-pals/references/builder-workflow.md +102 -0
  24. tavus_cli-0.3.4/skills/tavus-agentic-pals/references/chat-mode.md +93 -0
  25. {tavus_cli-0.3.2 → tavus_cli-0.3.4}/skills/tavus-agentic-pals/references/examples.md +1 -2
  26. {tavus_cli-0.3.2 → tavus_cli-0.3.4}/src/tavus_mcp/__init__.py +1 -1
  27. {tavus_cli-0.3.2 → tavus_cli-0.3.4}/src/tavus_mcp/cli/main.py +38 -106
  28. {tavus_cli-0.3.2 → tavus_cli-0.3.4}/src/tavus_mcp/sdk/client/http.py +52 -134
  29. tavus_cli-0.3.4/src/tavus_mcp/sdk/daily_transport.py +275 -0
  30. {tavus_cli-0.3.2 → tavus_cli-0.3.4}/src/tavus_mcp/sdk/env.py +24 -1
  31. tavus_cli-0.3.4/src/tavus_mcp/sdk/pal_urls.py +24 -0
  32. {tavus_cli-0.3.2 → tavus_cli-0.3.4}/src/tavus_mcp/sdk/patch.py +0 -4
  33. tavus_cli-0.3.4/src/tavus_mcp/sdk/recipes/build_and_verify.py +348 -0
  34. tavus_cli-0.3.4/src/tavus_mcp/sdk/recipes/carrier_builder.py +932 -0
  35. {tavus_cli-0.3.2 → tavus_cli-0.3.4}/src/tavus_mcp/sdk/schemas/pal.py +26 -4
  36. {tavus_cli-0.3.2 → tavus_cli-0.3.4}/src/tavus_mcp/server.py +83 -75
  37. {tavus_cli-0.3.2 → tavus_cli-0.3.4}/tests/integration/test_cli.py +36 -0
  38. {tavus_cli-0.3.2 → tavus_cli-0.3.4}/tests/integration/test_mcp_server.py +32 -2
  39. tavus_cli-0.3.4/tests/unit/test_build_and_verify.py +552 -0
  40. tavus_cli-0.3.4/tests/unit/test_builder.py +77 -0
  41. tavus_cli-0.3.4/tests/unit/test_daily_transport.py +178 -0
  42. {tavus_cli-0.3.2 → tavus_cli-0.3.4}/tests/unit/test_env.py +7 -0
  43. {tavus_cli-0.3.2 → tavus_cli-0.3.4}/tests/unit/test_pal_schema.py +31 -0
  44. {tavus_cli-0.3.2 → tavus_cli-0.3.4}/tests/unit/test_patch.py +11 -6
  45. tavus_cli-0.3.4/tests/unit/test_release_versions.py +40 -0
  46. {tavus_cli-0.3.2 → tavus_cli-0.3.4}/uv.lock +703 -686
  47. {tavus_cli-0.3.2 → tavus_cli-0.3.4}/workers/tavus-mcp/.dev.vars.example +1 -0
  48. {tavus_cli-0.3.2 → tavus_cli-0.3.4}/workers/tavus-mcp/package-lock.json +20 -2
  49. {tavus_cli-0.3.2 → tavus_cli-0.3.4}/workers/tavus-mcp/package.json +2 -1
  50. {tavus_cli-0.3.2 → tavus_cli-0.3.4}/workers/tavus-mcp/src/index.ts +2 -0
  51. tavus_cli-0.3.4/workers/tavus-mcp/src/oauth-grant.ts +82 -0
  52. tavus_cli-0.3.4/workers/tavus-mcp/src/oauth.ts +1085 -0
  53. {tavus_cli-0.3.2 → tavus_cli-0.3.4}/workers/tavus-mcp/src/tavus.ts +1153 -33
  54. tavus_cli-0.3.4/workers/tavus-mcp/src/version.ts +1 -0
  55. tavus_cli-0.3.4/workers/tavus-mcp/test/parity.test.ts +60 -0
  56. tavus_cli-0.3.4/workers/tavus-mcp/test/tavus.test.ts +981 -0
  57. {tavus_cli-0.3.2 → tavus_cli-0.3.4}/workers/tavus-mcp/tsconfig.json +1 -1
  58. {tavus_cli-0.3.2 → tavus_cli-0.3.4}/workers/tavus-mcp/wrangler.jsonc +26 -1
  59. tavus_cli-0.3.2/.github/workflows/deploy-cloudflare-worker.yml +0 -71
  60. tavus_cli-0.3.2/.github/workflows/pypi-cli.yml +0 -39
  61. tavus_cli-0.3.2/PKG-INFO +0 -230
  62. tavus_cli-0.3.2/README.md +0 -210
  63. tavus_cli-0.3.2/skills/tavus-agentic-pals/references/build-and-verify.md +0 -183
  64. tavus_cli-0.3.2/skills/tavus-agentic-pals/references/builder-workflow.md +0 -172
  65. tavus_cli-0.3.2/skills/tavus-agentic-pals/references/chat-mode.md +0 -313
  66. tavus_cli-0.3.2/src/tavus_mcp/sdk/recipes/build_and_verify.py +0 -630
  67. tavus_cli-0.3.2/tests/unit/test_build_and_verify.py +0 -523
  68. tavus_cli-0.3.2/tests/unit/test_builder.py +0 -155
  69. tavus_cli-0.3.2/tests/unit/test_conversation_chat.py +0 -82
  70. tavus_cli-0.3.2/workers/tavus-mcp/src/oauth.ts +0 -460
  71. tavus_cli-0.3.2/workers/tavus-mcp/test/tavus.test.ts +0 -442
  72. {tavus_cli-0.3.2 → tavus_cli-0.3.4}/.gitignore +0 -0
  73. {tavus_cli-0.3.2 → tavus_cli-0.3.4}/skills/tavus-agentic-pals/agents/openai.yaml +0 -0
  74. {tavus_cli-0.3.2 → tavus_cli-0.3.4}/src/tavus_mcp/cli/__init__.py +0 -0
  75. {tavus_cli-0.3.2 → tavus_cli-0.3.4}/src/tavus_mcp/sdk/__init__.py +0 -0
  76. {tavus_cli-0.3.2 → tavus_cli-0.3.4}/src/tavus_mcp/sdk/auth/__init__.py +0 -0
  77. {tavus_cli-0.3.2 → tavus_cli-0.3.4}/src/tavus_mcp/sdk/auth/keyring_store.py +0 -0
  78. {tavus_cli-0.3.2 → tavus_cli-0.3.4}/src/tavus_mcp/sdk/auth/oauth.py +0 -0
  79. {tavus_cli-0.3.2 → tavus_cli-0.3.4}/src/tavus_mcp/sdk/auth/session.py +0 -0
  80. {tavus_cli-0.3.2 → tavus_cli-0.3.4}/src/tavus_mcp/sdk/client/__init__.py +0 -0
  81. {tavus_cli-0.3.2 → tavus_cli-0.3.4}/src/tavus_mcp/sdk/errors.py +0 -0
  82. {tavus_cli-0.3.2 → tavus_cli-0.3.4}/src/tavus_mcp/sdk/recipes/__init__.py +0 -0
  83. {tavus_cli-0.3.2 → tavus_cli-0.3.4}/src/tavus_mcp/sdk/recipes/capabilities.py +0 -0
  84. {tavus_cli-0.3.2 → tavus_cli-0.3.4}/src/tavus_mcp/sdk/recipes/knowledge.py +0 -0
  85. {tavus_cli-0.3.2 → tavus_cli-0.3.4}/src/tavus_mcp/sdk/recipes/options.py +0 -0
  86. {tavus_cli-0.3.2 → tavus_cli-0.3.4}/src/tavus_mcp/sdk/recipes/quickstart.py +0 -0
  87. {tavus_cli-0.3.2 → tavus_cli-0.3.4}/src/tavus_mcp/sdk/recipes/scaffold_embed.py +0 -0
  88. {tavus_cli-0.3.2 → tavus_cli-0.3.4}/src/tavus_mcp/sdk/recipes/templates.py +0 -0
  89. {tavus_cli-0.3.2 → tavus_cli-0.3.4}/src/tavus_mcp/sdk/recipes/tool_reuse.py +0 -0
  90. {tavus_cli-0.3.2 → tavus_cli-0.3.4}/src/tavus_mcp/sdk/schemas/__init__.py +0 -0
  91. {tavus_cli-0.3.2 → tavus_cli-0.3.4}/src/tavus_mcp/sdk/schemas/file_manifest.py +0 -0
  92. {tavus_cli-0.3.2 → tavus_cli-0.3.4}/src/tavus_mcp/sdk/schemas/guardrail.py +0 -0
  93. {tavus_cli-0.3.2 → tavus_cli-0.3.4}/src/tavus_mcp/sdk/schemas/objective.py +0 -0
  94. {tavus_cli-0.3.2 → tavus_cli-0.3.4}/src/tavus_mcp/sdk/schemas/pronunciation.py +0 -0
  95. {tavus_cli-0.3.2 → tavus_cli-0.3.4}/src/tavus_mcp/sdk/schemas/tool.py +0 -0
  96. {tavus_cli-0.3.2 → tavus_cli-0.3.4}/tests/conftest.py +0 -0
  97. {tavus_cli-0.3.2 → tavus_cli-0.3.4}/tests/integration/test_client.py +0 -0
  98. {tavus_cli-0.3.2 → tavus_cli-0.3.4}/tests/integration/test_oauth.py +0 -0
  99. {tavus_cli-0.3.2 → tavus_cli-0.3.4}/tests/unit/test_auth.py +0 -0
  100. {tavus_cli-0.3.2 → tavus_cli-0.3.4}/tests/unit/test_capabilities.py +0 -0
  101. {tavus_cli-0.3.2 → tavus_cli-0.3.4}/tests/unit/test_guardrail_schema.py +0 -0
  102. {tavus_cli-0.3.2 → tavus_cli-0.3.4}/tests/unit/test_objective_schema.py +0 -0
  103. {tavus_cli-0.3.2 → tavus_cli-0.3.4}/tests/unit/test_pronunciation_schema.py +0 -0
  104. {tavus_cli-0.3.2 → tavus_cli-0.3.4}/tests/unit/test_scaffold_embed.py +0 -0
  105. {tavus_cli-0.3.2 → tavus_cli-0.3.4}/tests/unit/test_tool_reuse.py +0 -0
  106. {tavus_cli-0.3.2 → tavus_cli-0.3.4}/tests/unit/test_tool_schema.py +0 -0
@@ -8,28 +8,35 @@
8
8
  # TAVUS_PUBLIC_API_BASE_URL=https://test.rqh.tavusapi.com/v2
9
9
  # TAVUS_PORTAL_API_BASE_URL=https://test-api.tavus.io/api
10
10
  # TAVUS_DEV_PORTAL_URL=https://dev.platform.tavus.io
11
+ # TAVUS_PAL_MAKER_URL=https://dev.maker.tavus.io
11
12
  # STG defaults:
12
13
  # TAVUS_PUBLIC_API_BASE_URL=https://stg.rqh.tavusapi.com/v2
13
14
  # TAVUS_PORTAL_API_BASE_URL=https://stg-api.tavus.io/api
14
15
  # TAVUS_DEV_PORTAL_URL=https://stage.platform.tavus.io
16
+ # TAVUS_PAL_MAKER_URL=https://stage.maker.tavus.io
15
17
  # PROD defaults:
16
18
  # TAVUS_PUBLIC_API_BASE_URL=https://tavusapi.com/v2
17
19
  # TAVUS_PORTAL_API_BASE_URL=https://prod-api.tavus.io/api
18
20
  # TAVUS_DEV_PORTAL_URL=https://platform.tavus.io
21
+ # TAVUS_PAL_MAKER_URL=https://maker.tavus.io
19
22
  TAVUS_PUBLIC_API_BASE_URL=
20
23
  TAVUS_PORTAL_API_BASE_URL=
21
24
  TAVUS_DEV_PORTAL_URL=
25
+ TAVUS_PAL_MAKER_URL=
22
26
 
23
27
  # Optional per-env overrides. These beat the defaults but not the generic vars above.
24
28
  TAVUS_TEST_PUBLIC_API_BASE_URL=
25
29
  TAVUS_TEST_PORTAL_API_BASE_URL=
26
30
  TAVUS_TEST_DEV_PORTAL_URL=
31
+ TAVUS_TEST_PAL_MAKER_URL=
27
32
  TAVUS_STG_PUBLIC_API_BASE_URL=
28
33
  TAVUS_STG_PORTAL_API_BASE_URL=
29
34
  TAVUS_STG_DEV_PORTAL_URL=
35
+ TAVUS_STG_PAL_MAKER_URL=
30
36
  TAVUS_PROD_PUBLIC_API_BASE_URL=
31
37
  TAVUS_PROD_PORTAL_API_BASE_URL=
32
38
  TAVUS_PROD_DEV_PORTAL_URL=
39
+ TAVUS_PROD_PAL_MAKER_URL=
33
40
 
34
41
  # Optional auth fallback. If set, it wins over keyring for the selected env.
35
42
  TAVUS_API_KEY=
@@ -5,6 +5,7 @@ on:
5
5
  push:
6
6
  branches:
7
7
  - main
8
+ workflow_dispatch:
8
9
 
9
10
  concurrency:
10
11
  group: ci-${{ github.ref }}
@@ -25,6 +26,8 @@ jobs:
25
26
  python-version: ${{ matrix.python-version }}
26
27
  - name: Install uv
27
28
  run: pip install uv
29
+ - name: Check release versions before dependency sync
30
+ run: python scripts/check_release_versions.py
28
31
  - name: Install dependencies
29
32
  run: uv sync --extra dev
30
33
  - name: Ruff
@@ -38,3 +41,22 @@ jobs:
38
41
  run: uv run pytest -q
39
42
  - name: Build
40
43
  run: uv build
44
+
45
+ worker:
46
+ runs-on: ubuntu-latest
47
+ timeout-minutes: 10
48
+ defaults:
49
+ run:
50
+ working-directory: workers/tavus-mcp
51
+ steps:
52
+ - uses: actions/checkout@v4
53
+ - uses: actions/setup-node@v4
54
+ with:
55
+ node-version: 24
56
+ cache: npm
57
+ cache-dependency-path: workers/tavus-mcp/package-lock.json
58
+ - run: npm ci
59
+ - name: Type-check
60
+ run: npm run build
61
+ - name: Test hosted MCP and parity
62
+ run: npm test
@@ -0,0 +1,102 @@
1
+ name: Deploy Tavus MCP Worker to a lower environment
2
+
3
+ on:
4
+ workflow_dispatch:
5
+ inputs:
6
+ environment:
7
+ description: Lower environment to deploy
8
+ required: true
9
+ default: stg
10
+ type: choice
11
+ options:
12
+ - test
13
+ - stg
14
+ push:
15
+ branches:
16
+ - main
17
+
18
+ permissions:
19
+ contents: read
20
+ deployments: read
21
+ pull-requests: read
22
+
23
+ concurrency:
24
+ group: deploy-tavus-mcp-worker-${{ github.event_name == 'workflow_dispatch' && inputs.environment || 'stg' }}
25
+ cancel-in-progress: true
26
+
27
+ jobs:
28
+ deploy:
29
+ name: Deploy Worker to ${{ github.event_name == 'workflow_dispatch' && inputs.environment || 'stg' }}
30
+ # A release commit is the small version/changelog delta on top of the code
31
+ # already proven in staging. The release workflow promotes that exact tag.
32
+ if: >-
33
+ github.event_name == 'workflow_dispatch' ||
34
+ !startsWith(github.event.head_commit.message, 'chore(main): release')
35
+ runs-on: ubuntu-latest
36
+ timeout-minutes: 15
37
+ environment: ${{ github.event_name == 'workflow_dispatch' && inputs.environment || 'stg' }}
38
+ env:
39
+ CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
40
+ CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
41
+ CLOUDFLARE_ENV: ${{ github.event_name == 'workflow_dispatch' && inputs.environment || 'stg' }}
42
+ MCP_BASE_URL: https://mcp.tavus-preview.io
43
+ defaults:
44
+ run:
45
+ working-directory: workers/tavus-mcp
46
+
47
+ steps:
48
+ - name: Checkout
49
+ uses: actions/checkout@v4
50
+
51
+ - name: Set up Node.js
52
+ uses: actions/setup-node@v4
53
+ with:
54
+ node-version: 24
55
+ cache: npm
56
+ cache-dependency-path: workers/tavus-mcp/package-lock.json
57
+
58
+ - name: Validate deployment secrets
59
+ run: |
60
+ if [ -z "${CLOUDFLARE_API_TOKEN:-}" ]; then
61
+ echo "::error::Missing CLOUDFLARE_API_TOKEN for '$CLOUDFLARE_ENV'."
62
+ exit 1
63
+ fi
64
+ if [ -z "${CLOUDFLARE_ACCOUNT_ID:-}" ]; then
65
+ echo "::error::Missing CLOUDFLARE_ACCOUNT_ID for '$CLOUDFLARE_ENV'."
66
+ exit 1
67
+ fi
68
+
69
+ - name: Install dependencies
70
+ run: npm ci
71
+
72
+ - name: Type-check
73
+ run: npm run build
74
+
75
+ - name: Test
76
+ run: npm test
77
+
78
+ - name: Deploy Worker
79
+ run: npx wrangler deploy --env "$CLOUDFLARE_ENV"
80
+
81
+ - name: Smoke-test hosted OAuth and MCP routes
82
+ if: env.CLOUDFLARE_ENV == 'stg'
83
+ run: |
84
+ curl --fail --silent --show-error \
85
+ "$MCP_BASE_URL/.well-known/oauth-protected-resource/mcp" >/dev/null
86
+ curl --fail --silent --show-error \
87
+ "$MCP_BASE_URL/.well-known/oauth-authorization-server" >/dev/null
88
+ STATUS=$(curl --silent --output /tmp/tavus-mcp-response \
89
+ --write-out '%{http_code}' "$MCP_BASE_URL/mcp")
90
+ if [ "$STATUS" != "401" ]; then
91
+ echo "::error::$MCP_BASE_URL/mcp returned $STATUS; expected 401 without credentials."
92
+ cat /tmp/tavus-mcp-response
93
+ exit 1
94
+ fi
95
+
96
+ - name: Refresh Slack deployment tabs
97
+ if: always() && env.CLOUDFLARE_ENV == 'stg'
98
+ continue-on-error: true
99
+ uses: Tavus-Engineering/pr-changelog-action/status@main
100
+ with:
101
+ slack-bot-token: ${{ secrets.CVI_BOT_SLACK_TOKEN }}
102
+ github-token: ${{ secrets.GITHUB_TOKEN }}
@@ -17,7 +17,7 @@ jobs:
17
17
  uses: Tavus-Engineering/pr-changelog-action/review@main
18
18
  with:
19
19
  slack-bot-token: ${{ secrets.CVI_BOT_SLACK_TOKEN }}
20
- slack-channel-id: C0AFT2E9D5Y
20
+ slack-channel-id: C0AGPSMKQ3Z
21
21
  github-token: ${{ secrets.GITHUB_TOKEN }}
22
22
  repo: ${{ github.repository }}
23
23
  pr-number: ${{ github.event.pull_request.number }}
@@ -0,0 +1,333 @@
1
+ name: Release Tavus MCP
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+ workflow_dispatch:
8
+ inputs:
9
+ tag:
10
+ description: Existing GitHub release tag to retry, such as v0.3.4
11
+ required: true
12
+ type: string
13
+
14
+ permissions:
15
+ actions: write
16
+ contents: write
17
+ deployments: read
18
+ id-token: write
19
+ issues: write
20
+ pull-requests: write
21
+
22
+ concurrency:
23
+ group: release-tavus-mcp
24
+ cancel-in-progress: false
25
+
26
+ jobs:
27
+ release-please:
28
+ if: github.event_name == 'push'
29
+ runs-on: ubuntu-latest
30
+ outputs:
31
+ release_created: ${{ steps.release.outputs.release_created }}
32
+ tag_name: ${{ steps.release.outputs.tag_name }}
33
+ steps:
34
+ - name: Open or publish the release
35
+ id: release
36
+ uses: googleapis/release-please-action@v4.4.1
37
+ with:
38
+ token: ${{ github.token }}
39
+ config-file: release-please-config.json
40
+ manifest-file: .release-please-manifest.json
41
+
42
+ # release-please's generic TOML updater cannot target one package in
43
+ # uv.lock's [[package]] array. Re-lock the generated release branch so
44
+ # the local tavus-cli package matches pyproject.toml before CI runs.
45
+ - name: Checkout the release pull request
46
+ if: steps.release.outputs.prs_created == 'true'
47
+ uses: actions/checkout@v4
48
+ with:
49
+ ref: ${{ fromJSON(steps.release.outputs.pr).headBranchName }}
50
+ fetch-depth: 0
51
+
52
+ - name: Set up Python for the release lockfile
53
+ if: steps.release.outputs.prs_created == 'true'
54
+ uses: actions/setup-python@v5
55
+ with:
56
+ python-version: '3.11'
57
+
58
+ - name: Install uv for the release lockfile
59
+ if: steps.release.outputs.prs_created == 'true'
60
+ run: pip install uv
61
+
62
+ - name: Refresh the release lockfile
63
+ if: steps.release.outputs.prs_created == 'true'
64
+ run: |
65
+ set -euo pipefail
66
+ uv lock
67
+ if git diff --quiet -- uv.lock; then
68
+ echo "uv.lock already matches the release version."
69
+ exit 0
70
+ fi
71
+ git config user.name "github-actions[bot]"
72
+ git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
73
+ git add uv.lock
74
+ git commit -m "chore: refresh the release lockfile"
75
+ git push
76
+
77
+ # Pull requests created with GITHUB_TOKEN do not emit pull_request
78
+ # events. Dispatch both checks against the generated branch so its head
79
+ # still gets the normal CI and exact-staging evidence.
80
+ - name: Run checks for the release pull request
81
+ if: steps.release.outputs.prs_created == 'true'
82
+ env:
83
+ GH_TOKEN: ${{ github.token }}
84
+ RELEASE_PR: ${{ steps.release.outputs.pr }}
85
+ run: |
86
+ set -euo pipefail
87
+ BRANCH=$(jq -r '.headBranchName // empty' <<<"$RELEASE_PR")
88
+ NUMBER=$(jq -r '.number // empty' <<<"$RELEASE_PR")
89
+ if [[ ! "$BRANCH" =~ ^release-please ]]; then
90
+ echo "::error::Unexpected release pull request branch '$BRANCH'."
91
+ exit 1
92
+ fi
93
+ echo "Dispatching checks for release pull request #$NUMBER on $BRANCH."
94
+ gh workflow run ci.yml --repo "${{ github.repository }}" --ref "$BRANCH"
95
+ gh workflow run validate-staging-deployment.yml \
96
+ --repo "${{ github.repository }}" \
97
+ --ref "$BRANCH" \
98
+ -f main_sha="${{ github.sha }}"
99
+
100
+ - name: Refresh Slack deployment tabs
101
+ continue-on-error: true
102
+ uses: Tavus-Engineering/pr-changelog-action/status@main
103
+ with:
104
+ slack-bot-token: ${{ secrets.CVI_BOT_SLACK_TOKEN }}
105
+ github-token: ${{ secrets.GITHUB_TOKEN }}
106
+
107
+ preflight:
108
+ name: Validate and build the exact release tag
109
+ needs: release-please
110
+ if: >-
111
+ always() &&
112
+ (github.event_name == 'workflow_dispatch' ||
113
+ needs.release-please.outputs.release_created == 'true')
114
+ runs-on: ubuntu-latest
115
+ timeout-minutes: 20
116
+ env:
117
+ RELEASE_TAG: ${{ github.event_name == 'workflow_dispatch' && inputs.tag || needs.release-please.outputs.tag_name }}
118
+ GH_TOKEN: ${{ github.token }}
119
+ outputs:
120
+ release_tag: ${{ steps.release.outputs.release_tag }}
121
+ release_version: ${{ steps.release.outputs.release_version }}
122
+ release_sha: ${{ steps.release.outputs.release_sha }}
123
+ steps:
124
+ - name: Checkout the release tag
125
+ uses: actions/checkout@v4
126
+ with:
127
+ ref: ${{ env.RELEASE_TAG }}
128
+ fetch-depth: 0
129
+
130
+ - name: Resolve and validate the release
131
+ id: release
132
+ run: |
133
+ set -euo pipefail
134
+ if [ -z "$RELEASE_TAG" ] || [[ ! "$RELEASE_TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
135
+ echo "::error::Release tag '$RELEASE_TAG' must look like v0.3.4."
136
+ exit 1
137
+ fi
138
+ gh release view "$RELEASE_TAG" --repo "${{ github.repository }}" >/dev/null
139
+
140
+ RELEASE_SHA=$(git rev-parse HEAD)
141
+ TAG_SHA=$(git rev-list -n 1 "$RELEASE_TAG")
142
+ if [ "$RELEASE_SHA" != "$TAG_SHA" ]; then
143
+ echo "::error::$RELEASE_TAG points to $TAG_SHA, but checkout is $RELEASE_SHA."
144
+ exit 1
145
+ fi
146
+
147
+ VERSION=${RELEASE_TAG#v}
148
+ python scripts/check_release_versions.py --expected "$VERSION"
149
+
150
+ PARENT_SHA=$(git rev-parse "$RELEASE_SHA^")
151
+ UNEXPECTED=$(git diff --name-only "$PARENT_SHA" "$RELEASE_SHA" | grep -Ev \
152
+ '^(\.release-please-manifest\.json|CHANGELOG\.md|pyproject\.toml|uv\.lock|src/tavus_mcp/__init__\.py|workers/tavus-mcp/package\.json|workers/tavus-mcp/package-lock\.json|workers/tavus-mcp/src/version\.ts)$' || true)
153
+ if [ -n "$UNEXPECTED" ]; then
154
+ echo "::error::The release commit contains files that were not staged:"
155
+ echo "$UNEXPECTED"
156
+ exit 1
157
+ fi
158
+
159
+ DEPLOYMENTS=$(gh api "/repos/${{ github.repository }}/deployments?environment=stg&sha=$PARENT_SHA&per_page=20")
160
+ STAGED=false
161
+ while read -r DEPLOYMENT_ID; do
162
+ if gh api "/repos/${{ github.repository }}/deployments/$DEPLOYMENT_ID/statuses?per_page=20" \
163
+ --jq 'any(.[]; .state == "success")' | grep -qx true; then
164
+ STAGED=true
165
+ break
166
+ fi
167
+ done < <(jq -r '.[].id' <<<"$DEPLOYMENTS")
168
+ if [ "$STAGED" != true ]; then
169
+ echo "::error::Release parent $PARENT_SHA has no successful stg deployment."
170
+ exit 1
171
+ fi
172
+
173
+ echo "release_tag=$RELEASE_TAG" >>"$GITHUB_OUTPUT"
174
+ echo "release_version=$VERSION" >>"$GITHUB_OUTPUT"
175
+ echo "release_sha=$RELEASE_SHA" >>"$GITHUB_OUTPUT"
176
+ echo "Release $RELEASE_TAG promotes staged parent $PARENT_SHA."
177
+
178
+ - name: Set up Python
179
+ uses: actions/setup-python@v5
180
+ with:
181
+ python-version: '3.11'
182
+
183
+ - name: Install uv
184
+ run: pip install uv
185
+
186
+ - name: Install Python dependencies
187
+ run: uv sync --extra dev
188
+
189
+ - name: Ruff
190
+ run: uv run ruff check .
191
+
192
+ - name: Pytest
193
+ env:
194
+ COLUMNS: '200'
195
+ run: uv run pytest -q
196
+
197
+ - name: Build Python distributions
198
+ run: uv build
199
+
200
+ - name: Set up Node.js
201
+ uses: actions/setup-node@v4
202
+ with:
203
+ node-version: 24
204
+ cache: npm
205
+ cache-dependency-path: workers/tavus-mcp/package-lock.json
206
+
207
+ - name: Install Worker dependencies
208
+ working-directory: workers/tavus-mcp
209
+ run: npm ci
210
+
211
+ - name: Type-check Worker
212
+ working-directory: workers/tavus-mcp
213
+ run: npm run build
214
+
215
+ - name: Test Worker
216
+ working-directory: workers/tavus-mcp
217
+ run: npm test
218
+
219
+ - name: Upload Python distributions
220
+ uses: actions/upload-artifact@v4
221
+ with:
222
+ name: tavus-cli-${{ steps.release.outputs.release_version }}
223
+ path: dist/*
224
+ if-no-files-found: error
225
+ retention-days: 7
226
+
227
+ update-pending-board:
228
+ name: Show the production approval in Slack
229
+ needs: preflight
230
+ runs-on: ubuntu-latest
231
+ timeout-minutes: 7
232
+ steps:
233
+ - name: Wait for the production job to request approval
234
+ env:
235
+ GH_TOKEN: ${{ github.token }}
236
+ run: |
237
+ for ATTEMPT in $(seq 1 20); do
238
+ DEPLOYMENTS=$(gh api "/repos/${{ github.repository }}/deployments?environment=prod&sha=${{ needs.preflight.outputs.release_sha }}&per_page=10" || true)
239
+ while read -r DEPLOYMENT_ID; do
240
+ STATE=$(gh api "/repos/${{ github.repository }}/deployments/$DEPLOYMENT_ID/statuses?per_page=1" --jq '.[0].state // ""' || true)
241
+ if [ "$STATE" = "waiting" ]; then
242
+ echo "Production is waiting for approval."
243
+ exit 0
244
+ fi
245
+ if [ -n "$STATE" ]; then
246
+ echo "Production already moved to '$STATE'; refreshing the tabs now."
247
+ exit 0
248
+ fi
249
+ done < <(jq -r '.[].id' <<<"${DEPLOYMENTS:-[]}" 2>/dev/null || true)
250
+ sleep 15
251
+ done
252
+ echo "::warning::Production approval did not appear before the Slack refresh."
253
+
254
+ - name: Refresh Slack deployment tabs
255
+ continue-on-error: true
256
+ uses: Tavus-Engineering/pr-changelog-action/status@main
257
+ with:
258
+ slack-bot-token: ${{ secrets.CVI_BOT_SLACK_TOKEN }}
259
+ github-token: ${{ secrets.GITHUB_TOKEN }}
260
+
261
+ production:
262
+ name: Deploy Worker and publish CLI
263
+ needs: preflight
264
+ runs-on: ubuntu-latest
265
+ timeout-minutes: 20
266
+ environment: prod
267
+ env:
268
+ CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
269
+ CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
270
+ steps:
271
+ - name: Checkout the exact release tag
272
+ uses: actions/checkout@v4
273
+ with:
274
+ ref: ${{ needs.preflight.outputs.release_tag }}
275
+
276
+ - name: Set up Node.js
277
+ uses: actions/setup-node@v4
278
+ with:
279
+ node-version: 24
280
+ cache: npm
281
+ cache-dependency-path: workers/tavus-mcp/package-lock.json
282
+
283
+ - name: Install Worker dependencies
284
+ working-directory: workers/tavus-mcp
285
+ run: npm ci
286
+
287
+ - name: Deploy the hosted Worker
288
+ working-directory: workers/tavus-mcp
289
+ run: npx wrangler deploy --env prod
290
+
291
+ - name: Smoke-test production OAuth and MCP routes
292
+ run: |
293
+ curl --fail --silent --show-error \
294
+ https://mcp.tavus.io/.well-known/oauth-protected-resource/mcp >/dev/null
295
+ curl --fail --silent --show-error \
296
+ https://mcp.tavus.io/.well-known/oauth-authorization-server >/dev/null
297
+ STATUS=$(curl --silent --output /tmp/tavus-mcp-response \
298
+ --write-out '%{http_code}' https://mcp.tavus.io/mcp)
299
+ if [ "$STATUS" != "401" ]; then
300
+ echo "::error::https://mcp.tavus.io/mcp returned $STATUS; expected 401 without credentials."
301
+ cat /tmp/tavus-mcp-response
302
+ exit 1
303
+ fi
304
+
305
+ - name: Set up Python
306
+ uses: actions/setup-python@v5
307
+ with:
308
+ python-version: '3.11'
309
+
310
+ - name: Install uv
311
+ run: pip install uv
312
+
313
+ - name: Download Python distributions
314
+ uses: actions/download-artifact@v4
315
+ with:
316
+ name: tavus-cli-${{ needs.preflight.outputs.release_version }}
317
+ path: dist
318
+
319
+ - name: Publish Tavus CLI to PyPI
320
+ run: uv publish --trusted-publishing always --check-url https://pypi.org/simple/ dist/*
321
+
322
+ update-final-board:
323
+ name: Refresh Slack after production
324
+ needs: [preflight, update-pending-board, production]
325
+ if: always() && needs.preflight.result == 'success'
326
+ runs-on: ubuntu-latest
327
+ steps:
328
+ - name: Refresh Slack deployment tabs
329
+ continue-on-error: true
330
+ uses: Tavus-Engineering/pr-changelog-action/status@main
331
+ with:
332
+ slack-bot-token: ${{ secrets.CVI_BOT_SLACK_TOKEN }}
333
+ github-token: ${{ secrets.GITHUB_TOKEN }}
@@ -0,0 +1,52 @@
1
+ name: Tail Tavus MCP Worker
2
+
3
+ on:
4
+ workflow_dispatch:
5
+ inputs:
6
+ environment:
7
+ description: Cloudflare Worker environment to tail
8
+ required: true
9
+ default: prod
10
+ type: choice
11
+ options:
12
+ - test
13
+ - stg
14
+ - prod
15
+ seconds:
16
+ description: How long to stream logs before exiting
17
+ required: true
18
+ default: "120"
19
+ type: string
20
+
21
+ permissions:
22
+ contents: read
23
+
24
+ jobs:
25
+ tail:
26
+ runs-on: ubuntu-latest
27
+ environment: ${{ inputs.environment }}
28
+ env:
29
+ CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
30
+ CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
31
+ defaults:
32
+ run:
33
+ working-directory: workers/tavus-mcp
34
+
35
+ steps:
36
+ - name: Checkout
37
+ uses: actions/checkout@v4
38
+
39
+ - name: Setup Node.js
40
+ uses: actions/setup-node@v4
41
+ with:
42
+ node-version: 24
43
+ cache: npm
44
+ cache-dependency-path: workers/tavus-mcp/package-lock.json
45
+
46
+ - name: Install dependencies
47
+ run: npm ci
48
+
49
+ - name: Tail Worker logs
50
+ # timeout exits 124 when the window closes; that is the expected success path.
51
+ run: |
52
+ timeout "${{ inputs.seconds }}" npx wrangler tail --env "${{ inputs.environment }}" --format json || [ $? -eq 124 ]
@@ -0,0 +1,87 @@
1
+ name: Validate staging deployment
2
+
3
+ on:
4
+ pull_request:
5
+ branches: [main]
6
+ paths: [CHANGELOG.md]
7
+ workflow_dispatch:
8
+ inputs:
9
+ main_sha:
10
+ description: Exact main commit that the release pull request promotes
11
+ required: true
12
+ type: string
13
+
14
+ permissions:
15
+ actions: read
16
+ contents: read
17
+
18
+ concurrency:
19
+ group: validate-staging-${{ github.event.pull_request.number || github.run_id }}
20
+ cancel-in-progress: true
21
+
22
+ jobs:
23
+ validate-staging:
24
+ name: Validate the current main commit in staging
25
+ if: >-
26
+ github.event_name == 'workflow_dispatch' ||
27
+ startsWith(github.head_ref, 'release-please')
28
+ runs-on: ubuntu-latest
29
+ timeout-minutes: 30
30
+ steps:
31
+ - name: Wait for the exact staging deployment
32
+ env:
33
+ GH_TOKEN: ${{ github.token }}
34
+ EXPECTED_MAIN_SHA: ${{ github.event_name == 'workflow_dispatch' && inputs.main_sha || '' }}
35
+ run: |
36
+ while :; do
37
+ MAIN_TIP=$EXPECTED_MAIN_SHA
38
+ if [ -z "$MAIN_TIP" ]; then
39
+ MAIN_TIP=$(gh api "/repos/${{ github.repository }}/commits/main" \
40
+ --jq '.sha' || true)
41
+ fi
42
+ if [ -z "$MAIN_TIP" ]; then
43
+ echo "Could not resolve main; retrying."
44
+ sleep 30
45
+ continue
46
+ fi
47
+
48
+ RUN=$(gh api \
49
+ "/repos/${{ github.repository }}/actions/workflows/deploy-cloudflare-worker.yml/runs?branch=main&head_sha=$MAIN_TIP&event=push&per_page=1" \
50
+ --jq '.workflow_runs[0]' || true)
51
+ if [ -z "$RUN" ] || [ "$RUN" = "null" ]; then
52
+ echo "No staging run for $MAIN_TIP yet; waiting."
53
+ sleep 30
54
+ continue
55
+ fi
56
+
57
+ STATUS=$(jq -r '.status' <<<"$RUN")
58
+ CONCLUSION=$(jq -r '.conclusion' <<<"$RUN")
59
+ RUN_ID=$(jq -r '.id' <<<"$RUN")
60
+ URL=$(jq -r '.html_url' <<<"$RUN")
61
+ if [ "$STATUS" != "completed" ]; then
62
+ echo "Staging run for $MAIN_TIP is $STATUS; waiting. $URL"
63
+ sleep 30
64
+ continue
65
+ fi
66
+
67
+ if [ "$CONCLUSION" != "success" ]; then
68
+ echo "::error::Staging run for $MAIN_TIP concluded '$CONCLUSION'."
69
+ echo "View the run: $URL"
70
+ exit 1
71
+ fi
72
+
73
+ DEPLOY_JOB=$(gh api "/repos/${{ github.repository }}/actions/runs/$RUN_ID/jobs?per_page=100" \
74
+ --jq 'first(.jobs[] | select(.name == "Deploy Worker to stg")) // empty')
75
+ if [ -z "$DEPLOY_JOB" ]; then
76
+ echo "::error::Run $RUN_ID has no 'Deploy Worker to stg' job."
77
+ exit 1
78
+ fi
79
+ if [ "$(jq -r '.conclusion' <<<"$DEPLOY_JOB")" != "success" ]; then
80
+ echo "::error::The staging deploy job did not succeed."
81
+ echo "View the run: $URL"
82
+ exit 1
83
+ fi
84
+
85
+ echo "Staging deployed current main commit $MAIN_TIP successfully."
86
+ break
87
+ done
@@ -0,0 +1,3 @@
1
+ {
2
+ ".": "0.3.4"
3
+ }