Accept explicit LLM options offline
ober
74d3f8f8fc79b9f0730d1cd6b127e172ac2f28bd
--- a/README.md +++ b/README.md @@ -35,6 +35,7 @@ Supported options are `--config FILE`, `--count N`, `--all`, `--from REV`, `--exclude PREFIX`, `--min-lines N`, `--max-files N`, `--max-added-lines N`, `--max-note-bytes N`, `--threshold HUMAN,AI`, `--threshold HUMAN,UNCERTAIN,AI`, +`--no-llm`, `--llm`, `--provider NAME`, `--format table|json|jsonl|markdown`, `--metadata-only`, and `--heuristics-only`. @@ -53,6 +54,11 @@ and scores at or above `AI` are `likely-ai-assisted`. The three-value form is accepted for compatibility with `human,uncertain,ai` wording; the middle value is retained as a label boundary only and does not create a separate verdict. +`--no-llm` is the default. `--provider NAME` records the requested provider in +JSON output. `--llm` is accepted as an explicit request, but this release has no +active provider adapter; it emits a warning and still reports `llm_used:false` +and `network_used:false`. + By default, scans skip `vendor/`, `generated/`, `dist/`, `node_modules/`, and `.git/` paths. Use `--include PATH` or `--file PATH` to inspect one of those paths explicitly. `--include` and `--file` accept repository-relative pathspecs; @@ -81,8 +87,8 @@ JSON output includes: - `detector_version` - `config_hash` -- analysis provenance fields: `analysis_provider`, `llm_used`, and - `network_used` +- analysis provenance fields: `analysis_provider`, `provider`, `llm_used`, + and `network_used` - repository path - commit and parent IDs - author/committer-facing metadata --- a/main-binary.ss +++ b/main-binary.ss @@ -23,7 +23,7 @@ xs))) (def (usage) - (displayln "usage: jerboa main-binary.ss scan [PATH] [--config FILE] [--count N|--all] [--from REV] [--to REV] [--file PATH|--include PATH] [--exclude PREFIX] [--min-lines N] [--threshold HUMAN,AI] [--max-files N] [--max-added-lines N] [--max-note-bytes N] [--format table|json|jsonl|markdown]") + (displayln "usage: jerboa main-binary.ss scan [PATH] [--config FILE] [--count N|--all] [--from REV] [--to REV] [--file PATH|--include PATH] [--exclude PREFIX] [--min-lines N] [--threshold HUMAN,AI] [--no-llm|--llm] [--provider NAME] [--max-files N] [--max-added-lines N] [--max-note-bytes N] [--format table|json|jsonl|markdown]") (displayln " jerboa main-binary.ss explain REV [PATH] [--format json|markdown|table]") (displayln " jerboa main-binary.ss stats [PATH] [--count N]") (displayln " jerboa main-binary.ss verify-authorship [PATH] [--count N]")) @@ -467,6 +467,28 @@ (scan-config-max-note-bytes cfg))) (def current-config (finalize-config (default-scan-config))) +(def current-analysis-provider "offline-heuristics") +(def current-requested-provider "none") +(def current-llm-used? #f) +(def current-network-used? #f) +(def current-llm-requested? #f) + +(def (set-provider! name) + (set! current-requested-provider (if (string-empty? name) "none" name))) + +(def (request-llm!) + (set! current-llm-requested? #t)) + +(def (disable-llm!) + (set! current-llm-requested? #f) + (set! current-llm-used? #f) + (set! current-network-used? #f) + (set! current-analysis-provider "offline-heuristics")) + +(def (llm-warnings) + (if current-llm-requested? + (list (str "LLM analysis requested for provider " current-requested-provider "; no provider adapter is active, using offline heuristics")) + '())) (def (weight-for-category cfg category fallback) (cond [(same-public-string? category "text") (scan-config-text-weight cfg)] @@ -565,6 +587,7 @@ (append (commit-shape-warnings parents) (parent-history-warnings shallow? missing-parent?) (binary-change-warnings binary-count) + (llm-warnings) (if (null? files) '("no changed text files found or commit is unavailable") '()) (if (null? lines) '("no added UTF-8 patch lines available") '()) (limit-warning "files" file-count (scan-config-max-files current-config)) @@ -653,7 +676,8 @@ (cons 'evidence (signal-evidence s)) (cons 'limitations (signal-limitations s)))) (def (finding-json repo f) (list (cons 'detector_version detector-version) (cons 'config_hash (scan-config-hash current-config)) - (cons 'analysis_provider "offline-heuristics") (cons 'llm_used #f) (cons 'network_used #f) + (cons 'analysis_provider current-analysis-provider) (cons 'provider current-requested-provider) + (cons 'llm_used current-llm-used?) (cons 'network_used current-network-used?) (cons 'repository repo) (cons 'commit (finding-commit f)) (cons 'parent (finding-parent f)) (cons 'author_name (finding-author-name f)) (cons 'author_email (finding-author-email f)) (cons 'time (finding-time f)) (cons 'subject (finding-subject f)) (cons 'files (finding-files f)) @@ -665,7 +689,8 @@ (cons 'score (finding-score f)) (cons 'verdict (finding-verdict f)) (cons 'warnings (finding-warnings f)))) (def (report-json repo findings) (list (cons 'detector_version detector-version) (cons 'config_hash (scan-config-hash current-config)) - (cons 'analysis_provider "offline-heuristics") (cons 'llm_used #f) (cons 'network_used #f) + (cons 'analysis_provider current-analysis-provider) (cons 'provider current-requested-provider) + (cons 'llm_used current-llm-used?) (cons 'network_used current-network-used?) (cons 'repository repo) (cons 'count (length findings)) (cons 'findings (map (lambda (f) (finding-json repo f)) findings)))) @@ -892,6 +917,18 @@ (options-commit opts) (options-from opts) (options-to opts) (options-file opts) (options-min-lines opts) (options-metadata-only? opts) #t) path-set?)] + [(string=? (car xs) "--no-llm") + (begin + (disable-llm!) + (loop (cdr xs) opts path-set?))] + [(string=? (car xs) "--llm") + (begin + (request-llm!) + (loop (cdr xs) opts path-set?))] + [(and (string=? (car xs) "--provider") (pair? (cdr xs))) + (begin + (set-provider! (cadr xs)) + (loop (cddr xs) opts path-set?))] [(option-flag? (car xs)) (loop (cdr xs) opts path-set?)] [(and (string=? (options-command opts) "explain") (not (options-commit opts))) (loop (cdr xs) --- a/tests/fixture-smoke.sh +++ b/tests/fixture-smoke.sh @@ -42,6 +42,7 @@ json=$("$root/bin/jerboa-aigit" scan "$fixture" --format json --count 2) printf '%s\n' "$json" | grep -q '"count":2' printf '%s\n' "$json" | grep -q '"config_hash":"[0-9]' printf '%s\n' "$json" | grep -q '"analysis_provider":"offline-heuristics"' +printf '%s\n' "$json" | grep -q '"provider":"none"' printf '%s\n' "$json" | grep -q '"llm_used":false' printf '%s\n' "$json" | grep -q '"network_used":false' printf '%s\n' "$json" | grep -q '"verdict":"recorded-ai-authorship"' @@ -67,6 +68,18 @@ if printf '%s\n' "$heuristics" | grep -q '"verdict":"recorded-ai-authorship"'; t exit 1 fi +llm_json=$("$root/bin/jerboa-aigit" scan "$fixture" --format json --count 1 --llm --provider local) +printf '%s\n' "$llm_json" | grep -q '"provider":"local"' +printf '%s\n' "$llm_json" | grep -q '"llm_used":false' +printf '%s\n' "$llm_json" | grep -q '"network_used":false' +printf '%s\n' "$llm_json" | grep -q 'LLM analysis requested for provider local; no provider adapter is active, using offline heuristics' + +no_llm_json=$("$root/bin/jerboa-aigit" scan "$fixture" --format json --count 1 --llm --provider local --no-llm) +if printf '%s\n' "$no_llm_json" | grep -q 'LLM analysis requested'; then + echo "no-llm should disable requested LLM warning" >&2 + exit 1 +fi + metadata=$("$root/bin/jerboa-aigit" scan "$fixture" --format json --count 1 --metadata-only) printf '%s\n' "$metadata" | grep -q '"signals":\[\]' printf '%s\n' "$metadata" | grep -q '"score":0.0'