1# Reusable workflow: refreshes model profile data for any repo that uses the2# `langchain-profiles` CLI. Creates (or updates) a pull request with the3# resulting changes.4#5# Callers MUST set `permissions: { contents: write, pull-requests: write }` —6# reusable workflows cannot escalate the caller's token permissions.7#8# ── Example: external repo (langchain-google) ──────────────────────────9#10# jobs:11# refresh-profiles:12# uses: langchain-ai/langchain/.github/workflows/_refresh_model_profiles.yml@master13# with:14# providers: >-15# [16# {"provider":"google", "data_dir":"libs/genai/langchain_google_genai/data"},17# ]18# secrets:19# MODEL_PROFILE_BOT_APP_ID: ${{ secrets.MODEL_PROFILE_BOT_APP_ID }}20# MODEL_PROFILE_BOT_PRIVATE_KEY: ${{ secrets.MODEL_PROFILE_BOT_PRIVATE_KEY }}2122name: "Refresh Model Profiles (reusable)"2324on:25 workflow_call:26 inputs:27 providers:28 description: >-29 JSON array of objects, each with `provider` (models.dev provider ID)30 and `data_dir` (path relative to repo root where `_profiles.py` and31 `profile_augmentations.toml` live).32 required: true33 type: string34 cli-path:35 description: >-36 Path (relative to workspace) to an existing `libs/model-profiles`37 checkout. When set the workflow skips cloning the langchain repo and38 uses this directory for the CLI instead. Useful when the caller IS39 the langchain monorepo.40 required: false41 type: string42 default: ""43 cli-ref:44 description: >-45 Git ref of langchain-ai/langchain to checkout for the CLI.46 Ignored when `cli-path` is set.47 required: false48 type: string49 default: master50 add-paths:51 description: "Glob for files to stage in the PR commit."52 required: false53 type: string54 default: "**/_profiles.py"55 pr-branch:56 description: "Branch name for the auto-created PR."57 required: false58 type: string59 default: bot/refresh-model-profiles60 pr-title:61 description: "PR / commit title."62 required: false63 type: string64 default: "chore(model-profiles): refresh model profile data"65 pr-body:66 description: "PR body."67 required: false68 type: string69 default: |70 Automated refresh of model profile data via `langchain-profiles refresh`.7172 🤖 Generated by the `refresh_model_profiles` workflow.73 pr-labels:74 description: "Comma-separated labels to apply to the PR."75 required: false76 type: string77 default: bot78 secrets:79 MODEL_PROFILE_BOT_APP_ID:80 required: true81 MODEL_PROFILE_BOT_PRIVATE_KEY:82 required: true8384permissions:85 contents: write86 pull-requests: write8788jobs:89 refresh-profiles:90 name: refresh model profiles91 runs-on: ubuntu-latest92 steps:93 - name: "📋 Checkout"94 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v69596 - name: "📋 Checkout langchain-profiles CLI"97 if: inputs.cli-path == ''98 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v699 with:100 repository: langchain-ai/langchain101 ref: ${{ inputs.cli-ref }}102 sparse-checkout: libs/model-profiles103 path: _langchain-cli104105 - name: "🔧 Resolve CLI directory"106 id: cli107 env:108 CLI_PATH: ${{ inputs.cli-path }}109 run: |110 if [ -n "${CLI_PATH}" ]; then111 resolved="${GITHUB_WORKSPACE}/${CLI_PATH}"112 if [ ! -d "${resolved}" ]; then113 echo "::error::cli-path '${CLI_PATH}' does not exist at ${resolved}"114 exit 1115 fi116 echo "dir=${CLI_PATH}" >> "$GITHUB_OUTPUT"117 else118 echo "dir=_langchain-cli/libs/model-profiles" >> "$GITHUB_OUTPUT"119 fi120121 - name: "🐍 Set up Python + uv"122 uses: astral-sh/setup-uv@0ca8f610542aa7f4acaf39e65cf4eb3c35091883 # v7123 with:124 version: "0.5.25"125 python-version: "3.12"126 enable-cache: true127 cache-dependency-glob: "**/model-profiles/uv.lock"128129 - name: "📦 Install langchain-profiles CLI"130 working-directory: ${{ steps.cli.outputs.dir }}131 run: uv sync --frozen --no-group test --no-group dev --no-group lint132133 - name: "✅ Validate providers input"134 env:135 PROVIDERS_JSON: ${{ inputs.providers }}136 run: |137 echo "${PROVIDERS_JSON}" | jq -e 'type == "array" and length > 0' > /dev/null || {138 echo "::error::providers input must be a non-empty JSON array"139 exit 1140 }141 echo "${PROVIDERS_JSON}" | jq -e 'all(has("provider") and has("data_dir"))' > /dev/null || {142 echo "::error::every entry in providers must have 'provider' and 'data_dir' keys"143 exit 1144 }145146 - name: "🔄 Refresh profiles"147 env:148 PROVIDERS_JSON: ${{ inputs.providers }}149 run: |150 cli_dir="${GITHUB_WORKSPACE}/${{ steps.cli.outputs.dir }}"151 failed=""152 mapfile -t rows < <(echo "${PROVIDERS_JSON}" | jq -c '.[]')153 for row in "${rows[@]}"; do154 provider=$(echo "${row}" | jq -r '.provider')155 data_dir=$(echo "${row}" | jq -r '.data_dir')156 echo "--- Refreshing ${provider} -> ${data_dir} ---"157 if ! echo y | uv run --frozen --project "${cli_dir}" \158 langchain-profiles refresh \159 --provider "${provider}" \160 --data-dir "${GITHUB_WORKSPACE}/${data_dir}"; then161 echo "::error::Failed to refresh provider: ${provider}"162 failed="${failed} ${provider}"163 fi164 done165 if [ -n "${failed}" ]; then166 echo "::error::The following providers failed:${failed}"167 exit 1168 fi169170 - name: "🔑 Generate GitHub App token"171 id: app-token172 uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3173 with:174 app-id: ${{ secrets.MODEL_PROFILE_BOT_APP_ID }}175 private-key: ${{ secrets.MODEL_PROFILE_BOT_PRIVATE_KEY }}176177 - name: "🔀 Create pull request"178 id: create-pr179 uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8180 with:181 token: ${{ steps.app-token.outputs.token }}182 branch: ${{ inputs.pr-branch }}183 commit-message: ${{ inputs.pr-title }}184 title: ${{ inputs.pr-title }}185 body: ${{ inputs.pr-body }}186 labels: ${{ inputs.pr-labels }}187 add-paths: ${{ inputs.add-paths }}188189 - name: "📝 Summary"190 if: always()191 env:192 PR_OP: ${{ steps.create-pr.outputs.pull-request-operation }}193 PR_URL: ${{ steps.create-pr.outputs.pull-request-url }}194 JOB_STATUS: ${{ job.status }}195 run: |196 if [ "${PR_OP}" = "created" ] || [ "${PR_OP}" = "updated" ]; then197 echo "### ✅ PR ${PR_OP}: ${PR_URL}" >> "$GITHUB_STEP_SUMMARY"198 elif [ -z "${PR_OP}" ] && [ "${JOB_STATUS}" = "success" ]; then199 echo "### ⏭️ Skipped: profiles already up to date" >> "$GITHUB_STEP_SUMMARY"200 elif [ "${JOB_STATUS}" = "failure" ]; then201 echo "### ❌ Job failed — check step logs for details" >> "$GITHUB_STEP_SUMMARY"202 fi
Findings
✓ No findings reported for this file.