feat(composio): improve toolkit sync and connection handling (#507)

* Enhance release workflow with build target input and improved job structure

- Added a new input parameter `build_target` to specify the environment (production or staging) for the release process.
- Made `release_type` input optional with a default value of `patch`.
- Refactored job names and dependencies to reflect the new build target logic, including conditional steps for production and staging environments.
- Introduced a `resolve` step to determine build outputs based on the selected environment, enhancing the workflow's flexibility and clarity.
- Updated the `create-release` job to depend on the new `prepare-build` job, ensuring proper execution flow based on the build target.

* feat(composio): enhance Composio integration with toolkit management and testing

- Added `KNOWN_COMPOSIO_TOOLKITS` constant to facilitate access to available toolkits.
- Implemented unit tests for `useComposioIntegrations` to ensure correct behavior during toolkit and connection fetching, including error handling scenarios.
- Updated `Skills` page to utilize the new `KNOWN_COMPOSIO_TOOLKITS` for improved toolkit display logic.
- Refactored hooks to handle connection errors gracefully and maintain toolkit visibility.
- Enhanced backend integration by updating Composio client configuration to streamline toolkit management.

* refactor(dispatch): remove channel delivery instructions for Telegram

- Deleted the `channel_delivery_instructions` function, which provided response guidelines for Telegram messages. This change simplifies the message processing logic in the `process_channel_message` function by eliminating unnecessary instructions, enhancing clarity and maintainability.

* refactor(composio): simplify Composio client configuration and remove toggles

- Updated the `build_composio_client` function to remove unnecessary configuration checks, as Composio is always enabled when the user is signed in.
- Revised the `resolve_client` function to clarify error handling related to user authentication.
- Streamlined the `IntegrationsConfig` structure by removing toggles for Composio and related backend settings, ensuring a consistent configuration approach across integrations.
- Adjusted tests to reflect the removal of integration toggles and focus on core API key usage.

* refactor(composio): remove composio disabled state and improve error handling

- Eliminated the `disabled` state from the `useComposioIntegrations` hook, as Composio is always enabled when the user is authenticated.
- Updated error handling to surface backend connection issues directly, replacing previous checks for a disabled state.
- Revised tests to reflect the new error handling logic, ensuring clarity in toolkit fetch error reporting.

* refactor(integrations): update authentication handling for client configuration

- Revised the `build_client` function to prioritize app-session JWT for user authentication, enhancing clarity in the fallback mechanism to `config.api_key`.
- Improved error messages in `resolve_client` and `build_client` to provide clearer guidance on authentication issues related to session tokens.
- Streamlined comments and documentation to reflect the updated authentication flow, ensuring consistency across integration components.

* refactor(composio): unwrap CLI envelope for API responses

- Introduced a new `unwrapCliEnvelope` function to handle the response format from the Rust side, allowing for easier access to the flat shapes defined in `./types`.
- Updated `listToolkits`, `listConnections`, `listTools`, `authorize`, `deleteConnection`, and `execute` functions to utilize the new unwrapping logic, improving response handling consistency across the Composio API.
- Enhanced error handling by ensuring that responses without logs pass through unchanged, maintaining backward compatibility.

* refactor(skills_agent): update agent description and enhance Composio tool integration

- Revised the `when_to_use` description in `agent.toml` to clarify the role of the Skills Agent as a service integration specialist, emphasizing its capability to execute both Composio and QuickJS skill tools.
- Expanded the `prompt.md` documentation to detail available tool surfaces and typical Composio flow, improving clarity on how to interact with external services.
- Implemented category overrides for Composio tools in `tools.rs` to ensure they are recognized as part of the Skill category, allowing proper access through the skills sub-agent.
- Added tests to verify that Composio tools are correctly filtered and accessible by the skills sub-agent, ensuring robust integration and functionality.

* style: apply formatter output from pre-push checks

* refactor(tests): update Gmail and Notion integration tests for composio

- Refactored tests for the Skills page to integrate Gmail and Notion as composio tools, enhancing the testing framework.
- Removed mock data and streamlined the test setup to reflect the current state of available skills.
- Updated assertions to verify the rendering of connected and disconnected states for Gmail and Notion integrations, respectively.
- Improved clarity and maintainability of test cases by consolidating mock implementations and removing redundant code.

* refactor(skills): update toolkit categorization and enhance test assertions

- Modified the Skills component to assign categories dynamically based on toolkit metadata, improving organization of displayed tools.
- Updated test cases to reflect the new categorization, ensuring accurate rendering of tools under their respective categories instead of a generic 'Other' group.
- Enhanced assertions in tests to verify the presence of specific tools and their categories, improving test coverage and reliability.

* refactor(skills): streamline item creation in Skills component

- Simplified the item creation logic in the Skills component by removing unnecessary line breaks, enhancing code readability without altering functionality.
- This change contributes to cleaner code structure and maintainability in the Skills page.

* refactor(tests): enhance Gmail and Notion integration tests for improved clarity

- Updated the integration tests for Gmail and Notion on the Skills page to utilize the `within` function for more precise querying of elements within their respective sections.
- Improved test assertions to ensure that the connected and disconnected states are accurately verified, enhancing the reliability of the tests.
- Streamlined the test setup to better reflect the current structure of the Skills component, contributing to overall test maintainability.

* feat(skills): enhance Composio integration error handling and logging

- Added error handling for Composio integrations in the Skills component, displaying a user-friendly message when integration status is stale or an error occurs.
- Implemented logging in development mode to provide insights into the state of Composio toolkits and connections, aiding in debugging.
- Updated the item rendering logic to reflect the error state, ensuring users can retry fetching integrations when an error is detected.
- Enhanced tests to verify the display of error messages and the functionality of the retry mechanism, improving overall test coverage and reliability.
This commit is contained in:
Steven Enamakel
2026-04-11 12:15:45 -07:00
committed by GitHub
parent 362d0a014f
commit 759691e380
22 changed files with 883 additions and 524 deletions
+129 -33
View File
@@ -3,9 +3,18 @@ name: Release
on:
workflow_dispatch:
inputs:
build_target:
description: Build target environment
required: true
type: choice
default: production
options:
- production
- staging
release_type:
description: Version increment type
required: true
required: false
default: patch
type: choice
options:
- patch
@@ -17,13 +26,13 @@ permissions:
packages: write
concurrency:
group: release-main
group: release-${{ github.event.inputs.build_target || 'production' }}-main
cancel-in-progress: false
# ---------------------------------------------------------------------------
# Job dependency graph
#
# prepare-release
# prepare-build
# │
# ├─── create-release
# │ │
@@ -46,14 +55,17 @@ jobs:
# =========================================================================
# Phase 1: Version bump, commit, tag
# =========================================================================
prepare-release:
name: Prepare release commit and tag
prepare-build:
name: Prepare build context
runs-on: ubuntu-latest
environment: Production
outputs:
version: ${{ steps.bump.outputs.version }}
tag: ${{ steps.bump.outputs.tag }}
sha: ${{ steps.push.outputs.sha }}
version: ${{ steps.resolve.outputs.version }}
tag: ${{ steps.resolve.outputs.tag }}
sha: ${{ steps.resolve.outputs.sha }}
build_ref: ${{ steps.resolve.outputs.build_ref }}
release_enabled: ${{ steps.resolve.outputs.release_enabled }}
base_url: ${{ steps.resolve.outputs.base_url }}
steps:
- name: Enforce main branch
if: github.ref != 'refs/heads/main'
@@ -62,25 +74,35 @@ jobs:
exit 1
- name: Generate GitHub App token
if: inputs.build_target == 'production'
id: app-token
uses: tibdex/github-app-token@v1
with:
app_id: ${{ secrets.XGITHUB_APP_ID }}
private_key: ${{ secrets.XGITHUB_APP_PRIVATE_KEY }}
- name: Checkout main
- name: Checkout main for production release
if: inputs.build_target == 'production'
uses: actions/checkout@v4
with:
ref: main
fetch-depth: 0
token: ${{ steps.app-token.outputs.token }}
- name: Checkout main for staging build
if: inputs.build_target == 'staging'
uses: actions/checkout@v4
with:
ref: main
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 24.x
- name: Configure Git
if: inputs.build_target == 'production'
env:
APP_TOKEN: ${{ steps.app-token.outputs.token }}
run: |
@@ -92,13 +114,16 @@ jobs:
git pull origin main --ff-only
- name: Compute next version and sync release files
if: inputs.build_target == 'production'
id: bump
run: node scripts/release/bump-version.js "${{ inputs.release_type }}"
- name: Verify release version sync
if: inputs.build_target == 'production'
run: node scripts/release/verify-version-sync.js "${{ steps.bump.outputs.version }}"
- name: Ensure tag does not already exist
if: inputs.build_target == 'production'
env:
TAG: ${{ steps.bump.outputs.tag }}
run: |
@@ -113,6 +138,7 @@ jobs:
fi
- name: Commit, push and tag
if: inputs.build_target == 'production'
id: push
env:
VERSION: ${{ steps.bump.outputs.version }}
@@ -127,6 +153,33 @@ jobs:
echo "sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"
- name: Resolve build outputs
id: resolve
shell: bash
run: |
if [ "${{ inputs.build_target }}" = "production" ]; then
VERSION="${{ steps.bump.outputs.version }}"
TAG="${{ steps.bump.outputs.tag }}"
SHA="${{ steps.push.outputs.sha }}"
BUILD_REF="$TAG"
RELEASE_ENABLED="true"
BASE_URL="https://api.tinyhumans.ai/"
else
VERSION="$(node -p "require('./app/package.json').version")"
TAG=""
SHA="$(git rev-parse HEAD)"
BUILD_REF="$SHA"
RELEASE_ENABLED="false"
BASE_URL="https://staging-api.tinyhumans.ai/"
fi
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
echo "tag=$TAG" >> "$GITHUB_OUTPUT"
echo "sha=$SHA" >> "$GITHUB_OUTPUT"
echo "build_ref=$BUILD_REF" >> "$GITHUB_OUTPUT"
echo "release_enabled=$RELEASE_ENABLED" >> "$GITHUB_OUTPUT"
echo "base_url=$BASE_URL" >> "$GITHUB_OUTPUT"
# =========================================================================
# Phase 2: Create draft GitHub release
# =========================================================================
@@ -134,7 +187,8 @@ jobs:
name: Create GitHub release
runs-on: ubuntu-latest
environment: Production
needs: prepare-release
if: needs.prepare-build.outputs.release_enabled == 'true'
needs: prepare-build
outputs:
release_id: ${{ steps.create.outputs.release_id }}
upload_url: ${{ steps.create.outputs.upload_url }}
@@ -144,9 +198,9 @@ jobs:
uses: actions/github-script@v7
with:
script: |
const tag = '${{ needs.prepare-release.outputs.tag }}';
const version = '${{ needs.prepare-release.outputs.version }}';
const target = '${{ needs.prepare-release.outputs.sha }}';
const tag = '${{ needs.prepare-build.outputs.tag }}';
const version = '${{ needs.prepare-build.outputs.version }}';
const target = '${{ needs.prepare-build.outputs.sha }}';
const { owner, repo } = context.repo;
@@ -179,7 +233,12 @@ jobs:
# =========================================================================
build-desktop:
name: "Desktop: ${{ matrix.settings.artifact_suffix }}"
needs: [prepare-release, create-release]
needs: [prepare-build, create-release]
if: >-
always()
&& needs.prepare-build.result == 'success'
&& (needs.prepare-build.outputs.release_enabled != 'true'
|| needs.create-release.result == 'success')
runs-on: ${{ matrix.settings.platform }}
environment: Production
strategy:
@@ -205,10 +264,10 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- name: Checkout tag
- name: Checkout build ref
uses: actions/checkout@v4
with:
ref: ${{ needs.prepare-release.outputs.tag }}
ref: ${{ needs.prepare-build.outputs.build_ref }}
fetch-depth: 1
submodules: true
@@ -291,7 +350,7 @@ jobs:
id: config-overrides
uses: actions/github-script@v7
env:
BASE_URL: ${{ vars.BASE_URL }}
BASE_URL: ${{ needs.prepare-build.outputs.base_url }}
UPDATER_PUBLIC_KEY: ${{ secrets.UPDATER_PUBLIC_KEY || vars.UPDATER_PUBLIC_KEY }}
UPDATER_ENDPOINT: ${{ vars.UPDATER_ENDPOINT }}
UPDATER_REPO: tinyhumansai/openhuman
@@ -309,7 +368,7 @@ jobs:
run: yarn build
env:
NODE_ENV: production
VITE_BACKEND_URL: ${{ vars.BASE_URL }}
VITE_BACKEND_URL: ${{ needs.prepare-build.outputs.base_url }}
VITE_SENTRY_DSN: ${{ vars.VITE_SENTRY_DSN }}
VITE_DEBUG: ${{ vars.VITE_DEBUG }}
# OAuth guardrails (#365): block openhuman://oauth/success on outdated desktop builds.
@@ -383,6 +442,7 @@ jobs:
CORE_BIN_NAME: ${{ steps.core-paths.outputs.core_bin_name }}
- name: Build, package and upload to release
if: needs.prepare-build.outputs.release_enabled == 'true'
uses: tauri-apps/tauri-action@v0.6.2
id: tauri-build
env:
@@ -391,7 +451,8 @@ jobs:
# Signing + notarization are handled in a dedicated step afterwards
# where we sign everything with hardened runtime + entitlements
# (required by Apple notarization).
BASE_URL: ${{ vars.BASE_URL }}
BASE_URL: ${{ needs.prepare-build.outputs.base_url }}
VITE_BACKEND_URL: ${{ needs.prepare-build.outputs.base_url }}
MACOSX_DEPLOYMENT_TARGET: ${{ matrix.settings.platform == 'macos-latest' && '10.15' || '' }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD || secrets.UPDATER_PRIVATE_KEY_PASSWORD }}
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY || secrets.UPDATER_PRIVATE_KEY }}
@@ -408,6 +469,23 @@ jobs:
owner: tinyhumansai
repo: openhuman
- name: Build and package staging artifacts
if: needs.prepare-build.outputs.release_enabled != 'true'
shell: bash
env:
BASE_URL: ${{ needs.prepare-build.outputs.base_url }}
VITE_BACKEND_URL: ${{ needs.prepare-build.outputs.base_url }}
MACOSX_DEPLOYMENT_TARGET: ${{ matrix.settings.platform == 'macos-latest' && '10.15' || '' }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD || secrets.UPDATER_PRIVATE_KEY_PASSWORD }}
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY || secrets.UPDATER_PRIVATE_KEY }}
WITH_UPDATER: "true"
VITE_MINIMUM_SUPPORTED_APP_VERSION: ${{ vars.VITE_MINIMUM_SUPPORTED_APP_VERSION }}
VITE_LATEST_APP_DOWNLOAD_URL: ${{ vars.VITE_LATEST_APP_DOWNLOAD_URL }}
run: |
yarn --cwd app tauri build \
-c '${{ steps.config-overrides.outputs.json }}' \
${{ matrix.settings.args }}
- name: Locate macOS .app bundle
if: matrix.settings.platform == 'macos-latest'
id: locate-app
@@ -471,7 +549,7 @@ jobs:
"${{ steps.locate-app.outputs.bundle_dir }}"
- name: Re-upload notarized macOS artifacts to release
if: matrix.settings.platform == 'macos-latest'
if: matrix.settings.platform == 'macos-latest' && needs.prepare-build.outputs.release_enabled == 'true'
shell: bash
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -480,7 +558,7 @@ jobs:
bash scripts/release/upload-macos-artifacts.sh \
"${{ steps.locate-app.outputs.app_path }}" \
"${{ steps.locate-app.outputs.bundle_dir }}" \
"${{ needs.prepare-release.outputs.version }}" \
"${{ needs.prepare-build.outputs.version }}" \
"${{ matrix.settings.target }}"
- name: Verify macOS app bundle sidecar layout
@@ -511,7 +589,7 @@ jobs:
xcrun stapler validate "$APP_PATH" || echo "WARNING: Staple validation failed"
- name: Package CLI tarball and upload to release (unix)
if: matrix.settings.platform != 'windows-latest'
if: matrix.settings.platform != 'windows-latest' && needs.prepare-build.outputs.release_enabled == 'true'
shell: bash
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -533,16 +611,16 @@ jobs:
bash scripts/release/package-cli-tarball.sh \
"$BIN" \
"${{ needs.prepare-release.outputs.version }}" \
"${{ needs.prepare-build.outputs.version }}" \
"${{ matrix.settings.target }}"
- name: Package CLI zip and upload to release (windows)
if: matrix.settings.platform == 'windows-latest'
if: matrix.settings.platform == 'windows-latest' && needs.prepare-build.outputs.release_enabled == 'true'
shell: pwsh
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
$Version = "${{ needs.prepare-release.outputs.version }}"
$Version = "${{ needs.prepare-build.outputs.version }}"
$Target = "${{ matrix.settings.target }}"
$BinPath = "${{ steps.cli-paths.outputs.cli_path }}"
$ZipName = "openhuman-core-${Version}-${Target}.zip"
@@ -559,6 +637,15 @@ jobs:
gh release upload "v${Version}" $ZipName "${ZipName}.sha256" --repo tinyhumansai/openhuman --clobber
Write-Host "[package-cli] Uploaded $ZipName to v${Version}"
- name: Upload staging desktop bundles
if: needs.prepare-build.outputs.release_enabled != 'true'
uses: actions/upload-artifact@v4
with:
name: desktop-bundles-${{ matrix.settings.platform }}-${{ matrix.settings.artifact_suffix }}
path: |
app/src-tauri/target/${{ matrix.settings.target }}/release/bundle/**
target/${{ matrix.settings.target }}/release/bundle/**
- name: Upload standalone CLI artifacts
uses: actions/upload-artifact@v4
with:
@@ -571,17 +658,22 @@ jobs:
# =========================================================================
build-docker:
name: "Docker: build and push"
needs: [prepare-release, create-release]
needs: [prepare-build, create-release]
if: >-
always()
&& needs.prepare-build.result == 'success'
&& (needs.prepare-build.outputs.release_enabled != 'true'
|| needs.create-release.result == 'success')
runs-on: ubuntu-latest
environment: Production
env:
REGISTRY: ghcr.io
IMAGE_NAME: tinyhumansai/openhuman-core
steps:
- name: Checkout tag
- name: Checkout build ref
uses: actions/checkout@v4
with:
ref: ${{ needs.prepare-release.outputs.tag }}
ref: ${{ needs.prepare-build.outputs.build_ref }}
fetch-depth: 1
- name: Set up Docker Buildx
@@ -619,8 +711,11 @@ jobs:
name: Publish draft release
runs-on: ubuntu-latest
environment: Production
needs: [prepare-release, create-release, build-desktop, build-docker]
if: needs.build-desktop.result == 'success' && needs.build-docker.result == 'success'
needs: [prepare-build, create-release, build-desktop, build-docker]
if: >-
needs.prepare-build.outputs.release_enabled == 'true'
&& needs.build-desktop.result == 'success'
&& needs.build-docker.result == 'success'
steps:
- name: Validate required installer assets exist
uses: actions/github-script@v7
@@ -698,9 +793,10 @@ jobs:
name: Remove release and tag if build failed
runs-on: ubuntu-latest
environment: Production
needs: [prepare-release, create-release, build-desktop, build-docker]
needs: [prepare-build, create-release, build-desktop, build-docker]
if: >-
always()
&& needs.prepare-build.outputs.release_enabled == 'true'
&& needs.create-release.result == 'success'
&& (needs.build-desktop.result == 'failure' || needs.build-desktop.result == 'cancelled'
|| needs.build-docker.result == 'failure' || needs.build-docker.result == 'cancelled')
@@ -731,7 +827,7 @@ jobs:
script: |
const owner = context.repo.owner;
const repo = context.repo.repo;
const tag = '${{ needs.prepare-release.outputs.tag }}';
const tag = '${{ needs.prepare-build.outputs.tag }}';
try {
await github.rest.git.deleteRef({ owner, repo, ref: `tags/${tag}` });
@@ -747,7 +843,7 @@ jobs:
- name: Delete staging Docker image
continue-on-error: true
env:
TAG: ${{ needs.prepare-release.outputs.tag }}
TAG: ${{ needs.prepare-build.outputs.tag }}
run: |
PACKAGE="openhuman-core"
STAGING_TAG="staging-${TAG}"