feat: initial commit
This commit is contained in:
+382
@@ -0,0 +1,382 @@
|
||||
# Taskfile dla agentic-codemod-pipeline (https://taskfile.dev)
|
||||
#
|
||||
# Instalacja go-task:
|
||||
# macOS: brew install go-task
|
||||
# pip: pip install go-task-bin
|
||||
# linux: sh -c "$(curl -sSL https://taskfile.dev/install.sh)" -- -d -b ~/.local/bin
|
||||
#
|
||||
# Wszystkie zadania pracują w lokalnym .venv. Nic nie jest instalowane do systemowego
|
||||
# Pythona - na macOS z Homebrew kończyłoby się to błędem "externally-managed-environment"
|
||||
# (PEP 668), a w najlepszym razie zaśmieceniem interpretera systemowego.
|
||||
|
||||
version: "3"
|
||||
silent: true
|
||||
|
||||
# Lokalna konfiguracja developerska. Plik jest opcjonalny i nie trafia do repozytorium
|
||||
# (.gitignore). Zmienne wyeksportowane w powłoce mają pierwszeństwo przed .env,
|
||||
# więc `eval "$(task llm:env)"` zawsze wygrywa z tym, co tu wpisano.
|
||||
dotenv: [".env"]
|
||||
|
||||
vars:
|
||||
VENV: .venv
|
||||
BIN: "{{.VENV}}/bin"
|
||||
PY: "{{.VENV}}/bin/python"
|
||||
CLI: "{{.VENV}}/bin/agentic-codemod"
|
||||
FIXTURE: examples/fixtures/acme-app
|
||||
# Interpreter bazowy do utworzenia venva. Na macOS z systemowym Pythonem 3.9:
|
||||
# PYTHON=python3.12 task install
|
||||
PYTHON: '{{.PYTHON | default "python3"}}'
|
||||
# Backend LLM: auto (wykrycie platformy) | vllm-gpu | vllm-metal | ollama | mock
|
||||
LLM_BACKEND: '{{.LLM_BACKEND | default "auto"}}'
|
||||
LLM_RUN_DIR: .runs/llm
|
||||
COMPOSE: docker compose -f llm/docker-compose.yml
|
||||
BACKEND_PY: "{{.VENV}}/bin/python llm/scripts/backend.py"
|
||||
|
||||
env:
|
||||
PYTHONDONTWRITEBYTECODE: "1"
|
||||
|
||||
tasks:
|
||||
default:
|
||||
desc: Lista dostępnych zadań
|
||||
cmds:
|
||||
- task --list
|
||||
|
||||
# ------------------------------------------------------------- środowisko
|
||||
doctor:
|
||||
desc: Diagnostyka środowiska - uruchom to najpierw, gdy coś nie działa
|
||||
cmds:
|
||||
- |
|
||||
printf 'system : %s %s\n' "$(uname -s)" "$(uname -m)"
|
||||
printf 'interpreter bazowy: %s -> %s\n' "{{.PYTHON}}" "$({{.PYTHON}} -V 2>&1 || echo BRAK)"
|
||||
printf 'venv : %s\n' "$(test -x {{.PY}} && {{.PY}} -V 2>&1 || echo 'brak (uruchom: task install)')"
|
||||
printf 'uv : %s\n' "$(command -v uv >/dev/null 2>&1 && uv --version || echo 'brak (opcjonalny, przyspiesza instalację)')"
|
||||
printf 'git : %s\n' "$(git --version 2>/dev/null || echo BRAK)"
|
||||
printf 'ripgrep : %s\n' "$(rg --version 2>/dev/null | head -1 || echo 'brak (opcjonalny, używany przez skille)')"
|
||||
printf 'apm : %s\n' "$(apm --version 2>/dev/null || echo 'brak (potrzebny do apm install)')"
|
||||
printf 'agno : %s\n' "$(test -x {{.PY}} && {{.PY}} -c 'import agno; print(agno.__version__)' 2>/dev/null || echo 'brak')"
|
||||
|
||||
venv:
|
||||
internal: true
|
||||
preconditions:
|
||||
- sh: command -v {{.PYTHON}} >/dev/null 2>&1
|
||||
msg: |
|
||||
Nie znaleziono interpretera "{{.PYTHON}}".
|
||||
Na macOS: brew install python@3.12, a potem PYTHON=python3.12 task install
|
||||
- sh: '{{.PYTHON}} -c "import sys; sys.exit(0 if sys.version_info >= (3, 10) else 1)"'
|
||||
msg: |
|
||||
Wymagany Python 3.10 lub nowszy ({{.PYTHON}} jest starszy).
|
||||
macOS ma w systemie 3.9 - zainstaluj nowszy i wskaż go:
|
||||
brew install python@3.12 && PYTHON=python3.12 task install
|
||||
status:
|
||||
- test -x {{.PY}}
|
||||
cmds:
|
||||
- |
|
||||
# Niekompletny venv (przerwana instalacja, skasowany interpreter) jest gorszy
|
||||
# niż jego brak - narzędzia zgłaszają wtedy mylące błędy. Odtwarzamy go od zera.
|
||||
if [ -d "{{.VENV}}" ] && [ ! -x "{{.PY}}" ]; then
|
||||
echo "usuwam niekompletny {{.VENV}}"
|
||||
rm -rf "{{.VENV}}"
|
||||
fi
|
||||
if command -v uv >/dev/null 2>&1; then
|
||||
uv venv --python {{.PYTHON}} {{.VENV}}
|
||||
else
|
||||
{{.PYTHON}} -m venv {{.VENV}}
|
||||
fi
|
||||
|
||||
install:
|
||||
desc: Tworzy .venv i instaluje zależności (runtime + dev)
|
||||
deps: [venv]
|
||||
status:
|
||||
- test -f {{.VENV}}/.install-stamp
|
||||
- test {{.VENV}}/.install-stamp -nt pyproject.toml
|
||||
cmds:
|
||||
- |
|
||||
if command -v uv >/dev/null 2>&1; then
|
||||
uv pip install --python {{.PY}} -e ".[dev]"
|
||||
else
|
||||
{{.PY}} -m pip install --quiet --upgrade pip
|
||||
{{.PY}} -m pip install -e ".[dev]"
|
||||
fi
|
||||
- touch {{.VENV}}/.install-stamp
|
||||
- 'echo "gotowe: {{.CLI}}"'
|
||||
|
||||
context:
|
||||
desc: Instaluje i audytuje kontekst agentowy (APM), potem go wypisuje
|
||||
deps: [install]
|
||||
preconditions:
|
||||
- sh: command -v apm >/dev/null 2>&1
|
||||
msg: |
|
||||
Brak APM CLI. Instalacja:
|
||||
macOS: brew install apm (albo pip install apm-cli)
|
||||
inne: curl -sSL https://aka.ms/apm-unix | sh
|
||||
Repozytorium działa też bez APM CLI - wtedy używany jest wyłącznie
|
||||
lokalny kontekst z .apm/ (bez zależności zewnętrznych).
|
||||
cmds:
|
||||
- apm install
|
||||
- apm audit
|
||||
- "{{.CLI}} context"
|
||||
|
||||
context:show:
|
||||
desc: Wypisuje kontekst agentowy widziany przez silnik (bez apm install)
|
||||
deps: [install]
|
||||
cmds:
|
||||
- "{{.CLI}} context"
|
||||
|
||||
# ------------------------------------------------------------------ jakość
|
||||
lint:
|
||||
desc: Statyczna analiza i sprawdzenie formatowania
|
||||
deps: [install]
|
||||
cmds:
|
||||
- "{{.BIN}}/ruff check src tests llm"
|
||||
- "{{.BIN}}/ruff format --check src tests llm"
|
||||
|
||||
fmt:
|
||||
desc: Automatyczna poprawa formatowania i prostych błędów
|
||||
deps: [install]
|
||||
cmds:
|
||||
- "{{.BIN}}/ruff check --fix src tests llm"
|
||||
- "{{.BIN}}/ruff format src tests llm"
|
||||
|
||||
test:
|
||||
desc: Testy jednostkowe i integracyjne (bez modelu językowego)
|
||||
deps: [install]
|
||||
cmds:
|
||||
- "{{.BIN}}/pytest -q {{.CLI_ARGS}}"
|
||||
|
||||
test:cov:
|
||||
desc: Testy z raportem pokrycia
|
||||
deps: [install]
|
||||
cmds:
|
||||
- "{{.BIN}}/pytest -q --cov=agentic_codemod --cov-report=term-missing"
|
||||
|
||||
ci:
|
||||
desc: To, co sprawdza pipeline - uruchom przed pushem
|
||||
cmds:
|
||||
- task: lint
|
||||
- task: test
|
||||
- task: demo
|
||||
|
||||
# ------------------------------------------------------------- uruchomienia
|
||||
demo:
|
||||
desc: Pełny przebieg offline na fixture (bez LLM, bez sieci)
|
||||
deps: [install]
|
||||
vars:
|
||||
RUN_DIR: '{{.RUN_DIR | default ".runs/demo"}}'
|
||||
cmds:
|
||||
- |
|
||||
{{.CLI}} run \
|
||||
--repo {{.FIXTURE}} \
|
||||
--package acme-sdk --module acme --to-version 2.1.0 \
|
||||
--offline --run-dir "{{.RUN_DIR}}"
|
||||
- 'echo "diff: {{.RUN_DIR}}/changes.patch | manifest: {{.RUN_DIR}}/run.json"'
|
||||
|
||||
plan:
|
||||
desc: 'Sam plan zmian, bez modyfikacji kodu. Użycie: task plan -- --repo ../repo --package acme-sdk --to-version 2.1.0'
|
||||
deps: [install]
|
||||
cmds:
|
||||
- "{{.CLI}} run --plan-only --run-dir .runs/plan {{.CLI_ARGS}}"
|
||||
|
||||
run:
|
||||
desc: 'Przebieg z modelem. Użycie: task run -- --repo ../repo --package acme-sdk --to-version 2.1.0'
|
||||
deps: [install]
|
||||
preconditions:
|
||||
- sh: test -n "$CODEMOD_LLM_BASE_URL"
|
||||
msg: |
|
||||
Nie ustawiono CODEMOD_LLM_BASE_URL. Skopiuj .env.example do .env i wyeksportuj zmienne,
|
||||
albo uruchom przebieg deterministyczny: task demo
|
||||
cmds:
|
||||
- "{{.CLI}} run --run-dir .runs/local {{.CLI_ARGS}}"
|
||||
|
||||
# ------------------------------------------------------------------- LLM
|
||||
# Kontrakt jest jeden: endpoint zgodny z OpenAI pod CODEMOD_LLM_BASE_URL.
|
||||
# Backendy różnią się wyłącznie tym, jak ten endpoint powstaje.
|
||||
# Konfiguracja: llm/models.yml. Wybór ręczny: LLM_BACKEND=ollama task llm:up
|
||||
|
||||
llm:list:
|
||||
desc: Dostępne backendy LLM i który pasuje do tej maszyny
|
||||
deps: [install]
|
||||
cmds:
|
||||
- "{{.BACKEND_PY}} list"
|
||||
|
||||
llm:env:
|
||||
desc: 'Zmienne środowiskowe dla wybranego backendu. Użycie: eval "$(task llm:env)"'
|
||||
deps: [install]
|
||||
cmds:
|
||||
- "{{.BACKEND_PY}} env --backend {{.LLM_BACKEND}}"
|
||||
|
||||
llm:up:
|
||||
desc: Uruchamia backend LLM (autodetekcja platformy) i czeka na gotowość endpointu
|
||||
deps: [install]
|
||||
cmds:
|
||||
- mkdir -p {{.LLM_RUN_DIR}}
|
||||
- |
|
||||
set -e
|
||||
BACKEND="$({{.BACKEND_PY}} detect --requested {{.LLM_BACKEND}})"
|
||||
MODEL="$({{.BACKEND_PY}} get serve.model --backend "$BACKEND")"
|
||||
BASE_URL="$({{.BACKEND_PY}} get base_url --backend "$BACKEND")"
|
||||
echo "backend: $BACKEND | model: $MODEL | endpoint: $BASE_URL"
|
||||
|
||||
case "$BACKEND" in
|
||||
vllm-gpu)
|
||||
command -v docker >/dev/null || { echo "brak dockera - zainstaluj albo: LLM_BACKEND=ollama task llm:up" >&2; exit 1; }
|
||||
LLM_SERVE_MODEL="$MODEL" {{.COMPOSE}} --profile vllm-gpu up -d
|
||||
LOG=""
|
||||
;;
|
||||
vllm-metal)
|
||||
LOG="{{.LLM_RUN_DIR}}/vllm-metal.log"
|
||||
llm/scripts/vllm-metal.sh up "$MODEL" 8000 "$LOG" "{{.LLM_RUN_DIR}}/vllm-metal.pid"
|
||||
;;
|
||||
ollama)
|
||||
if command -v ollama >/dev/null 2>&1; then
|
||||
# macOS: natywna Ollama korzysta z Metala; w kontenerze liczyłaby na CPU
|
||||
curl -fsS --max-time 3 http://localhost:11434/api/version >/dev/null 2>&1 || {
|
||||
{{.PY}} llm/scripts/daemonize.py --pidfile "{{.LLM_RUN_DIR}}/ollama.pid" \
|
||||
--log "{{.LLM_RUN_DIR}}/ollama.log" -- ollama serve
|
||||
sleep 2
|
||||
}
|
||||
ollama pull "$MODEL"
|
||||
else
|
||||
{{.COMPOSE}} --profile ollama up -d
|
||||
{{.COMPOSE}} exec -T ollama ollama pull "$MODEL"
|
||||
fi
|
||||
LOG="{{.LLM_RUN_DIR}}/ollama.log"
|
||||
;;
|
||||
mock)
|
||||
LOG="{{.LLM_RUN_DIR}}/mock.log"
|
||||
{{.PY}} llm/scripts/daemonize.py --pidfile "{{.LLM_RUN_DIR}}/mock.pid" --log "$LOG" -- \
|
||||
{{.PY}} llm/mock_server.py --port 8077
|
||||
;;
|
||||
*)
|
||||
echo "nieznany backend: $BACKEND" >&2; exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "podgląd logów w drugim oknie: task llm:logs"
|
||||
llm/scripts/wait-for-endpoint.sh "$BASE_URL" "${LLM_WAIT_TIMEOUT:-900}" "$LOG"
|
||||
echo
|
||||
echo "gotowe. Wyeksportuj zmienne do swojej powłoki:"
|
||||
echo ' eval "$(task llm:env)"'
|
||||
|
||||
llm:down:
|
||||
desc: Zatrzymuje backend LLM
|
||||
deps: [install]
|
||||
cmds:
|
||||
- |
|
||||
BACKEND="$({{.BACKEND_PY}} detect --requested {{.LLM_BACKEND}})"
|
||||
case "$BACKEND" in
|
||||
vllm-gpu) {{.COMPOSE}} --profile vllm-gpu down ;;
|
||||
ollama)
|
||||
if [ -f "{{.LLM_RUN_DIR}}/ollama.pid" ]; then
|
||||
{{.PY}} llm/scripts/daemonize.py --pidfile "{{.LLM_RUN_DIR}}/ollama.pid" --log /dev/null --stop
|
||||
else
|
||||
{{.COMPOSE}} --profile ollama down
|
||||
fi
|
||||
;;
|
||||
vllm-metal) llm/scripts/vllm-metal.sh down "{{.LLM_RUN_DIR}}/vllm-metal.pid" ;;
|
||||
mock)
|
||||
{{.PY}} llm/scripts/daemonize.py --pidfile "{{.LLM_RUN_DIR}}/mock.pid" --log /dev/null --stop
|
||||
;;
|
||||
esac
|
||||
|
||||
llm:status:
|
||||
desc: Czy endpoint LLM odpowiada i jakie modele wystawia
|
||||
deps: [install]
|
||||
cmds:
|
||||
- |
|
||||
BASE_URL="$({{.BACKEND_PY}} get base_url --backend {{.LLM_BACKEND}})"
|
||||
echo "endpoint: $BASE_URL"
|
||||
curl -fsS --max-time 5 "$BASE_URL/models" || { echo "brak odpowiedzi - uruchom: task llm:up" >&2; exit 1; }
|
||||
|
||||
llm:smoke:
|
||||
desc: Jedno zapytanie do endpointu - sprawdza, czy model w ogóle odpowiada
|
||||
deps: [install]
|
||||
cmds:
|
||||
- |
|
||||
BASE_URL="$({{.BACKEND_PY}} get base_url --backend {{.LLM_BACKEND}})"
|
||||
MODEL="$({{.BACKEND_PY}} get serve.model --backend {{.LLM_BACKEND}})"
|
||||
curl -fsS --max-time 120 "$BASE_URL/chat/completions" \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d "{\"model\":\"$MODEL\",\"messages\":[{\"role\":\"user\",\"content\":\"Odpowiedz jednym slowem: dziala\"}],\"max_tokens\":16}"
|
||||
echo
|
||||
|
||||
llm:logs:
|
||||
desc: 'Logi backendu LLM na żywo. Warianty: TAIL=500, FOLLOW=false, GREP=wzorzec'
|
||||
deps: [install]
|
||||
vars:
|
||||
TAIL: '{{.TAIL | default "100"}}'
|
||||
FOLLOW: '{{.FOLLOW | default "true"}}'
|
||||
GREP: '{{.GREP | default ""}}'
|
||||
cmds:
|
||||
- |
|
||||
BACKEND="$({{.BACKEND_PY}} detect --requested {{.LLM_BACKEND}})"
|
||||
llm/scripts/logs.sh \
|
||||
--backend "$BACKEND" \
|
||||
--run-dir "{{.LLM_RUN_DIR}}" \
|
||||
--tail "{{.TAIL}}" \
|
||||
{{if eq .FOLLOW "false"}}--no-follow{{else}}--follow{{end}} \
|
||||
{{if .GREP}}--grep "{{.GREP}}"{{end}}
|
||||
|
||||
llm:logs:errors:
|
||||
desc: Same błędy i ostrzeżenia z logów backendu (jednorazowy zrzut)
|
||||
deps: [install]
|
||||
vars:
|
||||
TAIL: '{{.TAIL | default "2000"}}'
|
||||
cmds:
|
||||
- |
|
||||
BACKEND="$({{.BACKEND_PY}} detect --requested {{.LLM_BACKEND}})"
|
||||
llm/scripts/logs.sh --backend "$BACKEND" --run-dir "{{.LLM_RUN_DIR}}" \
|
||||
--tail "{{.TAIL}}" --no-follow \
|
||||
--grep "error|warning|traceback|exception|failed|out of memory|cuda|refused"
|
||||
|
||||
llm:logs:save:
|
||||
desc: 'Zrzut logów do pliku, do dołączenia w zgłoszeniu. Domyślnie .runs/llm/dump.log'
|
||||
deps: [install]
|
||||
vars:
|
||||
TAIL: '{{.TAIL | default "5000"}}'
|
||||
OUT: '{{.OUT | default ".runs/llm/dump.log"}}'
|
||||
cmds:
|
||||
- |
|
||||
BACKEND="$({{.BACKEND_PY}} detect --requested {{.LLM_BACKEND}})"
|
||||
llm/scripts/logs.sh --backend "$BACKEND" --run-dir "{{.LLM_RUN_DIR}}" \
|
||||
--tail "{{.TAIL}}" --save "{{.OUT}}"
|
||||
|
||||
llm:mock:
|
||||
desc: Atrapa serwera OpenAI na pierwszym planie (Ctrl-C kończy)
|
||||
deps: [install]
|
||||
cmds:
|
||||
- "{{.PY}} llm/mock_server.py --port 8077 --verbose"
|
||||
|
||||
# ------------------------------------------------------- przebiegi z LLM
|
||||
demo:llm:
|
||||
desc: Przebieg agentowy na fixture z aktualnym backendem LLM (domyślnie atrapa - deterministyczny)
|
||||
deps: [install]
|
||||
vars:
|
||||
RUN_DIR: '{{.RUN_DIR | default ".runs/demo-llm"}}'
|
||||
cmds:
|
||||
- task: llm:up
|
||||
vars: {LLM_BACKEND: "{{.LLM_BACKEND}}"}
|
||||
- |
|
||||
eval "$({{.BACKEND_PY}} env --backend {{.LLM_BACKEND}})"
|
||||
{{.CLI}} run \
|
||||
--repo {{.FIXTURE}} \
|
||||
--package acme-sdk --module acme --to-version 2.1.0 \
|
||||
--run-dir "{{.RUN_DIR}}"
|
||||
|
||||
test:llm:
|
||||
desc: Testy ścieżki agentowej na atrapie LLM (bez GPU i bez sieci)
|
||||
deps: [install]
|
||||
cmds:
|
||||
- "{{.BIN}}/pytest -q tests/test_llm_path.py"
|
||||
|
||||
# -------------------------------------------------------------- sprzątanie
|
||||
clean:
|
||||
desc: Usuwa artefakty przebiegów i cache narzędzi
|
||||
cmds:
|
||||
- rm -rf .runs workspace .pytest_cache .ruff_cache .coverage htmlcov
|
||||
- find . -type d -name __pycache__ -prune -exec rm -rf {} +
|
||||
|
||||
distclean:
|
||||
desc: Jak clean, plus .venv i zainstalowany kontekst APM
|
||||
deps: [clean]
|
||||
cmds:
|
||||
- rm -rf {{.VENV}} apm_modules *.egg-info src/*.egg-info
|
||||
Reference in New Issue
Block a user