Mirrowel
ci: mirrobot-agent hotfix
91acfb4
name: 'Bot Setup'
description: 'Performs all common setup steps for bot workflows, including token generation, git config, and dependency installation.'
inputs:
bot-app-id:
description: 'The ID of the GitHub App.'
required: true
bot-private-key:
description: 'The private key of the GitHub App.'
required: true
opencode-api-key:
description: 'The default API key, used for providers that do not have one defined in the custom providers JSON.'
required: false
opencode-model:
description: 'The main model to use (e.g., openai/gpt-4o or a custom one from custom providers JSON).'
required: true
opencode-fast-model:
description: 'Optional: The fast model for smaller tasks.'
required: false
custom-providers-json:
description: 'Optional: A JSON string defining custom providers. Use minifier to correctly format.'
required: false
outputs:
token:
description: "The generated GitHub App token."
value: ${{ steps.generate_token.outputs.token }}
runs:
using: "composite"
steps:
- name: Generate GitHub App Token
id: generate_token
uses: actions/create-github-app-token@v1
with:
app-id: ${{ inputs.bot-app-id }}
private-key: ${{ inputs.bot-private-key }}
- name: Configure Git for Bot
shell: bash
env:
GH_TOKEN: ${{ steps.generate_token.outputs.token }}
run: |
git config --global user.name "mirrobot-agent[bot]"
git config --global user.email "${{ inputs.bot-app-id }}+mirrobot-agent@users.noreply.github.com"
git config --global url."https://x-access-token:${{ steps.generate_token.outputs.token }}@github.com/".insteadOf "https://github.com/"
- name: Generate OpenCode Configuration
shell: bash
run: |
set -e # Exit immediately if a command fails
# --- HARDCODED TOGGLE ---
# Set to "true" to add 'reasoning_effort: "high"' to the main model's request body.
# Set to "false" to disable.
ADD_REASONING_EFFORT="true"
mkdir -p ~/.config/opencode
# --- INPUTS ---
MAIN_MODEL="${{ inputs.opencode-model }}"
FAST_MODEL="${{ inputs.opencode-fast-model }}"
DEFAULT_API_KEY="${{ inputs.opencode-api-key }}"
# Use command substitution with a heredoc to safely read the input into a variable.
# This is robust against complex characters and avoids creating a giant line of code that can break shell parsers.
CUSTOM_PROVIDERS=$(cat <<'EOF'
${{ inputs.custom-providers-json }}
EOF
)
# If the input was empty (or just whitespace), the variable will be empty. Set a default.
if [ -z "$CUSTOM_PROVIDERS" ]; then
CUSTOM_PROVIDERS='{}'
fi
# --- INITIAL CONFIG SETUP ---
mkdir -p ~/.config/opencode
CONFIG='{"$schema": "https://opencode.ai/config.json", "username": "mirrobot-agent", "autoupdate": true}'
# Merge custom provider definitions if they are not the empty default
if [ "$CUSTOM_PROVIDERS" != "{}" ]; then
echo "Custom provider definitions found. Merging into configuration."
CONFIG=$(jq --argjson customProviders "$CUSTOM_PROVIDERS" '. * {provider: $customProviders}' <<< "$CONFIG")
else
echo "No custom provider definitions supplied."
fi
# --- MODULAR FUNCTION TO CONFIGURE A MODEL ---
configure_model() {
local model_string="$1"
local config_key="$2"
local provider="${model_string%%/*}"
local model_name="${model_string#*/}"
# echo "--- Configuring ${config_key} with '${model_string}' ---"
# Check if the provider exists in the custom definitions
if jq -e --arg provider "$provider" '. | has($provider)' <<< "$CUSTOM_PROVIDERS" >/dev/null; then
echo "Provider found in custom definitions."
# CASE 2: Provider exists, but the model does not. This is an error.
if ! jq -e --arg provider "$provider" --arg modelName "$model_name" '.[$provider].models | has($modelName)' <<< "$CUSTOM_PROVIDERS" >/dev/null; then
echo "::error::Configuration error: Provider is defined, but model is not found within it. Aborting."
exit 1
fi
# CASE 1: Provider and model both exist. Use it as is.
# echo "Model '$model_name' also found. Setting '${config_key}' to '${model_string}'."
CONFIG=$(jq --arg key "$config_key" --arg val "$model_string" '.[$key] = $val' <<< "$CONFIG")
else
# CASE 3: Provider does not exist in custom definitions. Treat as a standard provider.
echo "Provider not found in custom definitions. Configuring as a standard provider."
CONFIG=$(jq --arg key "$config_key" --arg val "$model_string" '.[$key] = $val' <<< "$CONFIG")
echo "Setting default API key for provider."
CONFIG=$(jq \
--arg provider "$provider" \
--arg apiKey "$DEFAULT_API_KEY" \
'.provider[$provider].options.apiKey = $apiKey' <<< "$CONFIG")
if [[ "$config_key" == "model" && "$ADD_REASONING_EFFORT" == "true" ]]; then
echo "Reasoning effort toggle is ON. Applying to standard provider model."
CONFIG=$(jq \
--arg provider "$provider" \
--arg modelName "$model_name" \
'.provider[$provider].models[$modelName].options.reasoningEffort = "high"' <<< "$CONFIG")
fi
fi
}
# --- EXECUTION ---
configure_model "$MAIN_MODEL" "model"
if [ -n "$FAST_MODEL" ]; then
configure_model "$FAST_MODEL" "small_model"
fi
# --- FINALIZATION ---
echo "$CONFIG" > ~/.config/opencode/opencode.json
# echo "--- Generated OpenCode Configuration ---"
# jq . ~/.config/opencode/opencode.json
# echo "----------------------------------------"
echo "Successfully generated OpenCode configuration."
- name: Check for Python requirements file
id: check_requirements_file
shell: bash
run: |
if [ -f requirements.txt ]; then
echo "exists=true" >> $GITHUB_OUTPUT
else
echo "exists=false" >> $GITHUB_OUTPUT
fi
- name: Set up uv
if: steps.check_requirements_file.outputs.exists == 'true'
uses: astral-sh/setup-uv@v4
with:
enable-cache: true
cache-dependency-glob: "requirements.txt"
- name: Set up Python with uv
if: steps.check_requirements_file.outputs.exists == 'true'
shell: bash
run: |
uv python install 3.12
uv venv --python 3.12
- name: Install dependencies
if: steps.check_requirements_file.outputs.exists == 'true'
shell: bash
run: |
source .venv/bin/activate
uv pip install -r requirements.txt
- name: Install opencode
shell: bash
run: curl -fsSL https://opencode.ai/install | bash
- name: Ensure opencode directory exists
shell: bash
run: mkdir -p /home/runner/.local/share/opencode/project