Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .agents/scripts/cron-dispatch.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@

set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" || exit
# Source shared-constants for resolve_model_tier() (t132.7)
# shellcheck source=shared-constants.sh
source "${SCRIPT_DIR}/shared-constants.sh"

# Configuration
readonly CONFIG_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/aidevops"
readonly CONFIG_FILE="$CONFIG_DIR/cron-jobs.json"
Expand Down Expand Up @@ -256,6 +261,9 @@ main() {
timeout=$(echo "$job" | jq -r '.timeout // 600')
model=$(echo "$job" | jq -r '.model // "anthropic/claude-sonnet-4-20250514"')
notify=$(echo "$job" | jq -r '.notify // "none"')

# Resolve tier names to full model strings (t132.7)
model=$(resolve_model_tier "$model")

log_info "Job: $name"
log_info "Task: $task"
Expand Down
16 changes: 14 additions & 2 deletions .agents/scripts/cron-helper.sh
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ cmd_add() {
ensure_setup

local schedule="" task="" name="" notify="none" timeout="$DEFAULT_TIMEOUT"
local workdir="" model="$DEFAULT_MODEL" paused=false
local workdir="" model="$DEFAULT_MODEL" paused=false provider=""

while [[ $# -gt 0 ]]; do
case "$1" in
Expand All @@ -225,10 +225,20 @@ cmd_add() {
--timeout) [[ $# -lt 2 ]] && { log_error "--timeout requires a value"; return 1; }; timeout="$2"; shift 2 ;;
--workdir) [[ $# -lt 2 ]] && { log_error "--workdir requires a value"; return 1; }; workdir="$2"; shift 2 ;;
--model) [[ $# -lt 2 ]] && { log_error "--model requires a value"; return 1; }; model="$2"; shift 2 ;;
--provider) [[ $# -lt 2 ]] && { log_error "--provider requires a value"; return 1; }; provider="$2"; shift 2 ;;
--paused) paused=true; shift ;;
*) log_error "Unknown option: $1"; return 1 ;;
esac
done

# Resolve tier names to full model strings (t132.7)
model=$(resolve_model_tier "$model")

# Apply provider override if specified (t132.7)
if [[ -n "$provider" && "$model" == *"/"* ]]; then
local model_id="${model#*/}"
model="${provider}/${model_id}"
fi

# Validate required fields
if [[ -z "$schedule" ]]; then
Expand Down Expand Up @@ -672,7 +682,9 @@ ADD OPTIONS:
--notify mail|none Notification method (default: none)
--timeout SECONDS Max execution time (default: 600)
--workdir PATH Working directory (default: current)
--model MODEL AI model to use
--model TIER_OR_MODEL AI model: tier name (haiku/sonnet/opus/flash/pro/grok)
or full provider/model string
--provider PROVIDER Override provider (e.g., openrouter, google)
--paused Create in paused state

LOGS OPTIONS:
Expand Down
34 changes: 28 additions & 6 deletions .agents/scripts/runner-helper.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
# Each runner gets its own AGENTS.md (personality), config, and optional memory namespace.
#
# Usage:
# runner-helper.sh create <name> [--description "desc"] [--model provider/model] [--workdir path]
# runner-helper.sh run <name> "prompt" [--attach URL] [--model provider/model] [--format json] [--timeout N]
# runner-helper.sh create <name> [--description "desc"] [--model tier_or_model] [--provider name] [--workdir path]
# runner-helper.sh run <name> "prompt" [--attach URL] [--model tier_or_model] [--provider name] [--format json] [--timeout N]
# runner-helper.sh status <name>
# runner-helper.sh list [--format json]
# runner-helper.sh edit <name> # Open AGENTS.md in $EDITOR
Expand Down Expand Up @@ -235,17 +235,27 @@ cmd_create() {
return 1
fi

local description="" model="$DEFAULT_MODEL" workdir=""
local description="" model="$DEFAULT_MODEL" workdir="" provider=""

while [[ $# -gt 0 ]]; do
case "$1" in
--description) [[ $# -lt 2 ]] && { log_error "--description requires a value"; return 1; }; description="$2"; shift 2 ;;
--model) [[ $# -lt 2 ]] && { log_error "--model requires a value"; return 1; }; model="$2"; shift 2 ;;
--provider) [[ $# -lt 2 ]] && { log_error "--provider requires a value"; return 1; }; provider="$2"; shift 2 ;;
--workdir) [[ $# -lt 2 ]] && { log_error "--workdir requires a value"; return 1; }; workdir="$2"; shift 2 ;;
*) log_error "Unknown option: $1"; return 1 ;;
esac
done

# Resolve tier names to full model strings (t132.7)
model=$(resolve_model_tier "$model")

# Apply provider override if specified (t132.7)
if [[ -n "$provider" && "$model" == *"/"* ]]; then
local model_id="${model#*/}"
model="${provider}/${model_id}"
fi

if [[ -z "$description" ]]; then
description="Runner: $name"
fi
Expand Down Expand Up @@ -340,11 +350,13 @@ cmd_run() {
fi

local attach="" model="" format="" cmd_timeout="$DEFAULT_TIMEOUT" continue_session=false
local provider=""

while [[ $# -gt 0 ]]; do
case "$1" in
--attach) [[ $# -lt 2 ]] && { log_error "--attach requires a value"; return 1; }; attach="$2"; shift 2 ;;
--model) [[ $# -lt 2 ]] && { log_error "--model requires a value"; return 1; }; model="$2"; shift 2 ;;
--provider) [[ $# -lt 2 ]] && { log_error "--provider requires a value"; return 1; }; provider="$2"; shift 2 ;;
--format) [[ $# -lt 2 ]] && { log_error "--format requires a value"; return 1; }; format="$2"; shift 2 ;;
--timeout) [[ $# -lt 2 ]] && { log_error "--timeout requires a value"; return 1; }; cmd_timeout="$2"; shift 2 ;;
--continue|-c) continue_session=true; shift ;;
Expand All @@ -355,13 +367,20 @@ cmd_run() {
local dir
dir=$(runner_dir "$name")

# Resolve model (flag > config > default)
# Resolve model (flag > config > default), with tier name support (t132.7)
if [[ -z "$model" ]]; then
model=$(runner_config "$name" "model")
if [[ -z "$model" ]]; then
model="$DEFAULT_MODEL"
fi
fi
model=$(resolve_model_tier "$model")

# Apply provider override if specified (t132.7)
if [[ -n "$provider" && "$model" == *"/"* ]]; then
local model_id="${model#*/}"
model="${provider}/${model_id}"
fi

# Resolve workdir
local workdir
Expand Down Expand Up @@ -868,12 +887,15 @@ COMMANDS:

CREATE OPTIONS:
--description "DESC" Runner description
--model PROVIDER/MODEL AI model (default: anthropic/claude-sonnet-4-20250514)
--model TIER_OR_MODEL AI model: tier name (haiku/sonnet/opus/flash/pro/grok)
or full provider/model string (default: sonnet)
--provider PROVIDER Override provider (e.g., openrouter, google)
--workdir PATH Default working directory

RUN OPTIONS:
--attach URL Attach to running OpenCode server (avoids MCP cold boot)
--model PROVIDER/MODEL Override model for this run
--model TIER_OR_MODEL Override model: tier name or provider/model string
--provider PROVIDER Override provider for this run
--format json Output format (default or json)
--timeout SECONDS Max execution time (default: 600)
--continue, -c Continue previous session
Expand Down
88 changes: 88 additions & 0 deletions .agents/scripts/shared-constants.sh
Original file line number Diff line number Diff line change
Expand Up @@ -890,6 +890,94 @@ cleanup_sqlite_backups() {
# Export all constants for use in other scripts
# =============================================================================

# =============================================================================
# Model tier resolution (t132.7)
# Shared function for resolving tier names to full provider/model strings.
# Used by runner-helper.sh, cron-helper.sh, cron-dispatch.sh.
# Tries: 1) fallback-chain-helper.sh (availability-aware)
# 2) Static mapping (always works)
# =============================================================================

#######################################
# Resolve a model tier name to a full provider/model string (t132.7)
# Accepts both tier names (haiku, sonnet, opus, flash, pro, grok, coding, eval, health)
# and full provider/model strings (passed through unchanged).
# Returns the resolved model string on stdout.
#######################################
resolve_model_tier() {
local tier="${1:-coding}"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The repository style guide (line 11) requires declaring and assigning local variables on separate lines for safety under set -e. This line combines both operations.

Suggested change
local tier="${1:-coding}"
local tier
tier="${1:-coding}"
References
  1. Style guide rule 11 states to use local var="$1" pattern in functions, declaring and assigning separately for exit code safety. (link)


# If already a full provider/model string (contains /), return as-is
if [[ "$tier" == *"/"* ]]; then
echo "$tier"
return 0
fi

# Try fallback-chain-helper.sh for availability-aware resolution
local chain_helper="${BASH_SOURCE[0]%/*}/fallback-chain-helper.sh"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

To adhere to the repository style guide (line 11), please separate the declaration and assignment of this local variable.

Suggested change
local chain_helper="${BASH_SOURCE[0]%/*}/fallback-chain-helper.sh"
local chain_helper
chain_helper="${BASH_SOURCE[0]%/*}/fallback-chain-helper.sh"
References
  1. Style guide rule 11 states to use local var="$1" pattern in functions, declaring and assigning separately for exit code safety. (link)

if [[ -x "$chain_helper" ]]; then
local resolved
resolved=$("$chain_helper" resolve "$tier" --quiet 2>/dev/null) || true
if [[ -n "$resolved" ]]; then
echo "$resolved"
return 0
fi
fi

# Static fallback: map tier names to concrete models
case "$tier" in
opus|coding)
echo "anthropic/claude-opus-4-6"
;;
sonnet|eval)
echo "anthropic/claude-sonnet-4-20250514"
;;
haiku|health)
echo "anthropic/claude-3-5-haiku-20241022"
;;
flash)
echo "google/gemini-2.5-flash-preview-05-20"
;;
pro)
echo "google/gemini-2.5-pro-preview-06-05"
;;
grok)
echo "xai/grok-3"
;;
*)
# Unknown tier — return as-is (may be a model name without provider)
echo "$tier"
;;
esac

return 0
}

#######################################
# Detect available AI CLI backends (t132.7)
# Returns a newline-separated list of available backends.
# Checks: opencode, claude
#######################################
detect_ai_backends() {
local -a backends=()

if command -v opencode &>/dev/null; then
backends+=("opencode")
fi

if command -v claude &>/dev/null; then
backends+=("claude")
fi

if [[ ${#backends[@]} -eq 0 ]]; then
echo "none"
return 1
fi

printf '%s\n' "${backends[@]}"
return 0
}

# This ensures all constants are available when this file is sourced
export CONTENT_TYPE_JSON CONTENT_TYPE_FORM USER_AGENT
export HTTP_OK HTTP_CREATED HTTP_BAD_REQUEST HTTP_UNAUTHORIZED HTTP_FORBIDDEN HTTP_NOT_FOUND HTTP_INTERNAL_ERROR
Expand Down
Loading