mirror of
https://github.com/zsh-users/zsh-autosuggestions.git
synced 2026-02-09 16:41:32 +01:00
refactor(ai): replace empty buffer with min input
- Replace ZSH_AUTOSUGGEST_ALLOW_EMPTY_BUFFER with AI_MIN_INPUT - Add ZSH_AUTOSUGGEST_AI_DEBUG environment variable - Add debug logging function to diagnose failures - Update history lines default from 20 to 5 - Update pwd history preference default to no Min input provides clearer semantics: set to 0 for empty-buffer suggestions or higher to require minimum input. Debug logging helps diagnose missing suggestions by showing API request flow. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
81672cc7fe
commit
cd66c5695a
7 changed files with 142 additions and 52 deletions
22
README.md
22
README.md
|
|
@ -130,17 +130,17 @@ export ZSH_AUTOSUGGEST_STRATEGY=(ai history)
|
||||||
| `ZSH_AUTOSUGGEST_AI_ENDPOINT` | `https://api.openai.com/v1` | API base URL |
|
| `ZSH_AUTOSUGGEST_AI_ENDPOINT` | `https://api.openai.com/v1` | API base URL |
|
||||||
| `ZSH_AUTOSUGGEST_AI_MODEL` | `gpt-3.5-turbo` | Model name to use |
|
| `ZSH_AUTOSUGGEST_AI_MODEL` | `gpt-3.5-turbo` | Model name to use |
|
||||||
| `ZSH_AUTOSUGGEST_AI_TIMEOUT` | `5` | Request timeout in seconds |
|
| `ZSH_AUTOSUGGEST_AI_TIMEOUT` | `5` | Request timeout in seconds |
|
||||||
| `ZSH_AUTOSUGGEST_AI_MIN_INPUT` | `0` | Minimum input length before querying |
|
| `ZSH_AUTOSUGGEST_AI_MIN_INPUT` | `1` | Minimum input length before querying (`0` enables empty-buffer suggestions) |
|
||||||
| `ZSH_AUTOSUGGEST_AI_HISTORY_LINES` | `20` | Number of recent history lines to send as context |
|
| `ZSH_AUTOSUGGEST_AI_HISTORY_LINES` | `5` | Number of recent history lines to send as context |
|
||||||
| `ZSH_AUTOSUGGEST_AI_PREFER_PWD_HISTORY` | `yes` | Prioritize history from current directory |
|
| `ZSH_AUTOSUGGEST_AI_PREFER_PWD_HISTORY` | `no` | Prioritize history from current directory |
|
||||||
| `ZSH_AUTOSUGGEST_ALLOW_EMPTY_BUFFER` | (unset) | Set to any value to enable suggestions on empty buffer (requires zsh 5.3+) |
|
| `ZSH_AUTOSUGGEST_AI_DEBUG` | (unset) | Prints AI debug logs to stderr when enabled |
|
||||||
|
|
||||||
#### Empty Buffer Suggestions
|
#### Empty Buffer Suggestions
|
||||||
|
|
||||||
By default, suggestions only appear when you start typing. You can enable suggestions on an empty command line by setting `ZSH_AUTOSUGGEST_ALLOW_EMPTY_BUFFER`:
|
By default, suggestions only appear when you start typing. You can enable suggestions on an empty command line by setting `ZSH_AUTOSUGGEST_AI_MIN_INPUT=0`:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
export ZSH_AUTOSUGGEST_ALLOW_EMPTY_BUFFER=1
|
export ZSH_AUTOSUGGEST_AI_MIN_INPUT=0
|
||||||
export ZSH_AUTOSUGGEST_AI_API_KEY="your-api-key-here"
|
export ZSH_AUTOSUGGEST_AI_API_KEY="your-api-key-here"
|
||||||
export ZSH_AUTOSUGGEST_STRATEGY=(ai history)
|
export ZSH_AUTOSUGGEST_STRATEGY=(ai history)
|
||||||
```
|
```
|
||||||
|
|
@ -151,6 +151,16 @@ export ZSH_AUTOSUGGEST_STRATEGY=(ai history)
|
||||||
- Traditional strategies (history, completion) don't benefit from empty buffer suggestions
|
- Traditional strategies (history, completion) don't benefit from empty buffer suggestions
|
||||||
- **Cost consideration:** With AI strategy, this will make an API request on every new prompt, which may increase API costs
|
- **Cost consideration:** With AI strategy, this will make an API request on every new prompt, which may increase API costs
|
||||||
|
|
||||||
|
#### AI Debug Logs
|
||||||
|
|
||||||
|
If AI suggestions are not appearing, enable debug logs:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
export ZSH_AUTOSUGGEST_AI_DEBUG=1
|
||||||
|
```
|
||||||
|
|
||||||
|
Debug logs are printed to stderr with the prefix `[zsh-autosuggestions ai]`.
|
||||||
|
|
||||||
#### Examples
|
#### Examples
|
||||||
|
|
||||||
**OpenAI (default):**
|
**OpenAI (default):**
|
||||||
|
|
|
||||||
|
|
@ -195,7 +195,7 @@ EOFCURL
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'empty buffer suggestions' do
|
context 'empty buffer suggestions' do
|
||||||
let(:options) { ["ZSH_AUTOSUGGEST_AI_API_KEY=test-key", "ZSH_AUTOSUGGEST_ALLOW_EMPTY_BUFFER=1", "ZSH_AUTOSUGGEST_STRATEGY=(ai)"] }
|
let(:options) { ["ZSH_AUTOSUGGEST_AI_API_KEY=test-key", "ZSH_AUTOSUGGEST_AI_MIN_INPUT=0", "ZSH_AUTOSUGGEST_STRATEGY=(ai)"] }
|
||||||
|
|
||||||
let(:before_sourcing) do
|
let(:before_sourcing) do
|
||||||
-> {
|
-> {
|
||||||
|
|
@ -216,8 +216,8 @@ EOFCURL
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'empty buffer without flag' do
|
context 'empty buffer with default min input' do
|
||||||
let(:options) { ["ZSH_AUTOSUGGEST_AI_API_KEY=test-key", "ZSH_AUTOSUGGEST_STRATEGY=(ai history)"] }
|
let(:options) { ["ZSH_AUTOSUGGEST_AI_API_KEY=test-key", "ZSH_AUTOSUGGEST_AI_MIN_INPUT=1", "ZSH_AUTOSUGGEST_STRATEGY=(ai history)"] }
|
||||||
|
|
||||||
let(:before_sourcing) do
|
let(:before_sourcing) do
|
||||||
-> {
|
-> {
|
||||||
|
|
@ -232,7 +232,7 @@ EOFCURL
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'does not suggest on empty buffer by default' do
|
it 'does not suggest on empty buffer when min input is 1' do
|
||||||
with_history('git status') do
|
with_history('git status') do
|
||||||
sleep 0.5
|
sleep 0.5
|
||||||
expect(session.content).to_not match(/git status/)
|
expect(session.content).to_not match(/git status/)
|
||||||
|
|
@ -323,7 +323,7 @@ EOFCURL
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'dual prompt modes' do
|
context 'dual prompt modes' do
|
||||||
let(:options) { ["ZSH_AUTOSUGGEST_AI_API_KEY=test-key", "ZSH_AUTOSUGGEST_ALLOW_EMPTY_BUFFER=1", "ZSH_AUTOSUGGEST_STRATEGY=(ai)"] }
|
let(:options) { ["ZSH_AUTOSUGGEST_AI_API_KEY=test-key", "ZSH_AUTOSUGGEST_AI_MIN_INPUT=0", "ZSH_AUTOSUGGEST_STRATEGY=(ai)"] }
|
||||||
|
|
||||||
context 'empty buffer mode' do
|
context 'empty buffer mode' do
|
||||||
let(:before_sourcing) do
|
let(:before_sourcing) do
|
||||||
|
|
@ -366,7 +366,7 @@ EOFCURL
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'temperature configuration' do
|
context 'temperature configuration' do
|
||||||
let(:options) { ["ZSH_AUTOSUGGEST_AI_API_KEY=test-key", "ZSH_AUTOSUGGEST_ALLOW_EMPTY_BUFFER=1", "ZSH_AUTOSUGGEST_STRATEGY=(ai)"] }
|
let(:options) { ["ZSH_AUTOSUGGEST_AI_API_KEY=test-key", "ZSH_AUTOSUGGEST_AI_MIN_INPUT=0", "ZSH_AUTOSUGGEST_STRATEGY=(ai)"] }
|
||||||
|
|
||||||
let(:before_sourcing) do
|
let(:before_sourcing) do
|
||||||
-> {
|
-> {
|
||||||
|
|
|
||||||
|
|
@ -108,17 +108,17 @@ typeset -g ZSH_AUTOSUGGEST_AI_MODEL='gpt-3.5-turbo'
|
||||||
typeset -g ZSH_AUTOSUGGEST_AI_TIMEOUT=5
|
typeset -g ZSH_AUTOSUGGEST_AI_TIMEOUT=5
|
||||||
|
|
||||||
# Minimum input length before querying AI
|
# Minimum input length before querying AI
|
||||||
|
# Set to 0 to allow empty-buffer AI suggestions
|
||||||
(( ! ${+ZSH_AUTOSUGGEST_AI_MIN_INPUT} )) &&
|
(( ! ${+ZSH_AUTOSUGGEST_AI_MIN_INPUT} )) &&
|
||||||
typeset -g ZSH_AUTOSUGGEST_AI_MIN_INPUT=0
|
typeset -g ZSH_AUTOSUGGEST_AI_MIN_INPUT=1
|
||||||
|
|
||||||
# Number of recent history lines to include as context
|
# Number of recent history lines to include as context
|
||||||
(( ! ${+ZSH_AUTOSUGGEST_AI_HISTORY_LINES} )) &&
|
(( ! ${+ZSH_AUTOSUGGEST_AI_HISTORY_LINES} )) &&
|
||||||
typeset -g ZSH_AUTOSUGGEST_AI_HISTORY_LINES=20
|
typeset -g ZSH_AUTOSUGGEST_AI_HISTORY_LINES=5
|
||||||
|
|
||||||
# Prefer history entries from current directory
|
# Prefer history entries from current directory
|
||||||
(( ! ${+ZSH_AUTOSUGGEST_AI_PREFER_PWD_HISTORY} )) &&
|
(( ! ${+ZSH_AUTOSUGGEST_AI_PREFER_PWD_HISTORY} )) &&
|
||||||
typeset -g ZSH_AUTOSUGGEST_AI_PREFER_PWD_HISTORY=yes
|
typeset -g ZSH_AUTOSUGGEST_AI_PREFER_PWD_HISTORY=no
|
||||||
|
|
||||||
# Allow suggestions on empty buffer (opt-in, for AI strategy)
|
# Enable AI debug logs to stderr (opt-in).
|
||||||
# Set to any value to enable. Unset by default.
|
# Set to any value except 0/false/no/off to enable.
|
||||||
# Uses (( ${+VAR} )) pattern like ZSH_AUTOSUGGEST_MANUAL_REBIND
|
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,8 @@ add-zsh-hook precmd _zsh_autosuggest_start
|
||||||
|
|
||||||
_zsh_autosuggest_line_init() {
|
_zsh_autosuggest_line_init() {
|
||||||
emulate -L zsh
|
emulate -L zsh
|
||||||
if (( ${+ZSH_AUTOSUGGEST_ALLOW_EMPTY_BUFFER} )) && \
|
local min_input="${ZSH_AUTOSUGGEST_AI_MIN_INPUT:-1}"
|
||||||
|
if (( min_input == 0 )) && \
|
||||||
(( ! ${+_ZSH_AUTOSUGGEST_DISABLED} )); then
|
(( ! ${+_ZSH_AUTOSUGGEST_DISABLED} )); then
|
||||||
_zsh_autosuggest_fetch
|
_zsh_autosuggest_fetch
|
||||||
fi
|
fi
|
||||||
|
|
|
||||||
|
|
@ -35,8 +35,8 @@ _zsh_autosuggest_strategy_ai_gather_context() {
|
||||||
# Reset options to defaults and enable LOCAL_OPTIONS
|
# Reset options to defaults and enable LOCAL_OPTIONS
|
||||||
emulate -L zsh
|
emulate -L zsh
|
||||||
|
|
||||||
local max_lines="${ZSH_AUTOSUGGEST_AI_HISTORY_LINES:-20}"
|
local max_lines="${ZSH_AUTOSUGGEST_AI_HISTORY_LINES:-5}"
|
||||||
local prefer_pwd="${ZSH_AUTOSUGGEST_AI_PREFER_PWD_HISTORY:-yes}"
|
local prefer_pwd="${ZSH_AUTOSUGGEST_AI_PREFER_PWD_HISTORY:-no}"
|
||||||
local pwd_basename="${PWD:t}"
|
local pwd_basename="${PWD:t}"
|
||||||
local -a context_lines
|
local -a context_lines
|
||||||
local -a pwd_lines
|
local -a pwd_lines
|
||||||
|
|
@ -141,6 +141,18 @@ _zsh_autosuggest_strategy_ai_normalize() {
|
||||||
printf '%s' "$result"
|
printf '%s' "$result"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_zsh_autosuggest_strategy_ai_debug_log() {
|
||||||
|
# Reset options to defaults and enable LOCAL_OPTIONS
|
||||||
|
emulate -L zsh
|
||||||
|
|
||||||
|
local debug="${ZSH_AUTOSUGGEST_AI_DEBUG:-0}"
|
||||||
|
case "${debug:l}" in
|
||||||
|
0|false|no|off) return ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
print -ru2 -- "[zsh-autosuggestions ai] $1"
|
||||||
|
}
|
||||||
|
|
||||||
_zsh_autosuggest_strategy_ai() {
|
_zsh_autosuggest_strategy_ai() {
|
||||||
# Reset options to defaults and enable LOCAL_OPTIONS
|
# Reset options to defaults and enable LOCAL_OPTIONS
|
||||||
emulate -L zsh
|
emulate -L zsh
|
||||||
|
|
@ -149,14 +161,23 @@ _zsh_autosuggest_strategy_ai() {
|
||||||
local buffer="$1"
|
local buffer="$1"
|
||||||
|
|
||||||
# Early return if API key not set (opt-in gate)
|
# Early return if API key not set (opt-in gate)
|
||||||
[[ -z "$ZSH_AUTOSUGGEST_AI_API_KEY" ]] && return
|
if [[ -z "$ZSH_AUTOSUGGEST_AI_API_KEY" ]]; then
|
||||||
|
_zsh_autosuggest_strategy_ai_debug_log "API key not set; skipping AI request."
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
# Early return if curl or jq not available
|
# Early return if curl or jq not available
|
||||||
[[ -z "${commands[curl]}" ]] || [[ -z "${commands[jq]}" ]] && return
|
if [[ -z "${commands[curl]}" ]] || [[ -z "${commands[jq]}" ]]; then
|
||||||
|
_zsh_autosuggest_strategy_ai_debug_log "Missing dependency: curl and jq are required."
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
# Early return if input too short
|
# Early return if input too short
|
||||||
local min_input="${ZSH_AUTOSUGGEST_AI_MIN_INPUT:-0}"
|
local min_input="${ZSH_AUTOSUGGEST_AI_MIN_INPUT:-1}"
|
||||||
[[ ${#buffer} -lt $min_input ]] && return
|
if [[ ${#buffer} -lt $min_input ]]; then
|
||||||
|
_zsh_autosuggest_strategy_ai_debug_log "Input shorter than ZSH_AUTOSUGGEST_AI_MIN_INPUT=$min_input."
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
# Gather history context
|
# Gather history context
|
||||||
local -a context
|
local -a context
|
||||||
|
|
@ -222,6 +243,8 @@ _zsh_autosuggest_strategy_ai() {
|
||||||
local timeout="${ZSH_AUTOSUGGEST_AI_TIMEOUT:-5}"
|
local timeout="${ZSH_AUTOSUGGEST_AI_TIMEOUT:-5}"
|
||||||
local response
|
local response
|
||||||
|
|
||||||
|
_zsh_autosuggest_strategy_ai_debug_log "Requesting $endpoint (model=${ZSH_AUTOSUGGEST_AI_MODEL:-gpt-3.5-turbo}, input_len=${#buffer})."
|
||||||
|
|
||||||
response=$(curl --silent --max-time "$timeout" \
|
response=$(curl --silent --max-time "$timeout" \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
-H "Authorization: Bearer $ZSH_AUTOSUGGEST_AI_API_KEY" \
|
-H "Authorization: Bearer $ZSH_AUTOSUGGEST_AI_API_KEY" \
|
||||||
|
|
@ -230,26 +253,39 @@ _zsh_autosuggest_strategy_ai() {
|
||||||
"$endpoint" 2>/dev/null)
|
"$endpoint" 2>/dev/null)
|
||||||
|
|
||||||
# Check curl exit status
|
# Check curl exit status
|
||||||
[[ $? -ne 0 ]] && return
|
local curl_status=$?
|
||||||
|
if [[ $curl_status -ne 0 ]]; then
|
||||||
|
_zsh_autosuggest_strategy_ai_debug_log "curl failed with exit code $curl_status."
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
# Split response body from HTTP status
|
# Split response body from HTTP status
|
||||||
local http_code="${response##*$'\n'}"
|
local http_code="${response##*$'\n'}"
|
||||||
local body="${response%$'\n'*}"
|
local body="${response%$'\n'*}"
|
||||||
|
|
||||||
# Early return on non-2xx status
|
# Early return on non-2xx status
|
||||||
[[ "$http_code" != 2* ]] && return
|
if [[ "$http_code" != 2* ]]; then
|
||||||
|
_zsh_autosuggest_strategy_ai_debug_log "HTTP $http_code from AI endpoint."
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
# Extract content from JSON response
|
# Extract content from JSON response
|
||||||
local content
|
local content
|
||||||
content=$(printf '%s' "$body" | jq -r '.choices[0].message.content // empty' 2>/dev/null)
|
content=$(printf '%s' "$body" | jq -r '.choices[0].message.content // empty' 2>/dev/null)
|
||||||
|
|
||||||
# Early return if extraction failed
|
# Early return if extraction failed
|
||||||
[[ -z "$content" ]] && return
|
if [[ -z "$content" ]]; then
|
||||||
|
_zsh_autosuggest_strategy_ai_debug_log "No suggestion content in API response."
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
# Normalize response
|
# Normalize response
|
||||||
local normalized
|
local normalized
|
||||||
normalized="$(_zsh_autosuggest_strategy_ai_normalize "$content" "$buffer")"
|
normalized="$(_zsh_autosuggest_strategy_ai_normalize "$content" "$buffer")"
|
||||||
|
|
||||||
# Set suggestion
|
# Set suggestion
|
||||||
[[ -n "$normalized" ]] && suggestion="$normalized"
|
if [[ -n "$normalized" ]]; then
|
||||||
|
suggestion="$normalized"
|
||||||
|
_zsh_autosuggest_strategy_ai_debug_log "AI suggestion accepted: '$normalized'."
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,9 @@ _zsh_autosuggest_disable() {
|
||||||
# Enable suggestions
|
# Enable suggestions
|
||||||
_zsh_autosuggest_enable() {
|
_zsh_autosuggest_enable() {
|
||||||
unset _ZSH_AUTOSUGGEST_DISABLED
|
unset _ZSH_AUTOSUGGEST_DISABLED
|
||||||
|
local min_input="${ZSH_AUTOSUGGEST_AI_MIN_INPUT:-1}"
|
||||||
|
|
||||||
if (( $#BUFFER )) || (( ${+ZSH_AUTOSUGGEST_ALLOW_EMPTY_BUFFER} )); then
|
if (( $#BUFFER )) || (( min_input == 0 )); then
|
||||||
_zsh_autosuggest_fetch
|
_zsh_autosuggest_fetch
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
@ -73,11 +74,12 @@ _zsh_autosuggest_modify() {
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Get a new suggestion if the buffer is not empty after modification
|
# Get a new suggestion if the buffer is not empty after modification
|
||||||
|
local min_input="${ZSH_AUTOSUGGEST_AI_MIN_INPUT:-1}"
|
||||||
if (( $#BUFFER > 0 )); then
|
if (( $#BUFFER > 0 )); then
|
||||||
if [[ -z "$ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE" ]] || (( $#BUFFER <= $ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE )); then
|
if [[ -z "$ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE" ]] || (( $#BUFFER <= $ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE )); then
|
||||||
_zsh_autosuggest_fetch
|
_zsh_autosuggest_fetch
|
||||||
fi
|
fi
|
||||||
elif (( ${+ZSH_AUTOSUGGEST_ALLOW_EMPTY_BUFFER} )); then
|
elif (( min_input == 0 )); then
|
||||||
_zsh_autosuggest_fetch
|
_zsh_autosuggest_fetch
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
@ -100,8 +102,9 @@ _zsh_autosuggest_suggest() {
|
||||||
emulate -L zsh
|
emulate -L zsh
|
||||||
|
|
||||||
local suggestion="$1"
|
local suggestion="$1"
|
||||||
|
local min_input="${ZSH_AUTOSUGGEST_AI_MIN_INPUT:-1}"
|
||||||
|
|
||||||
if [[ -n "$suggestion" ]] && { (( $#BUFFER )) || (( ${+ZSH_AUTOSUGGEST_ALLOW_EMPTY_BUFFER} )); }; then
|
if [[ -n "$suggestion" ]] && { (( $#BUFFER )) || (( min_input == 0 )); }; then
|
||||||
POSTDISPLAY="${suggestion#$BUFFER}"
|
POSTDISPLAY="${suggestion#$BUFFER}"
|
||||||
else
|
else
|
||||||
POSTDISPLAY=
|
POSTDISPLAY=
|
||||||
|
|
|
||||||
|
|
@ -134,20 +134,20 @@ typeset -g ZSH_AUTOSUGGEST_AI_MODEL='gpt-3.5-turbo'
|
||||||
typeset -g ZSH_AUTOSUGGEST_AI_TIMEOUT=5
|
typeset -g ZSH_AUTOSUGGEST_AI_TIMEOUT=5
|
||||||
|
|
||||||
# Minimum input length before querying AI
|
# Minimum input length before querying AI
|
||||||
|
# Set to 0 to allow empty-buffer AI suggestions
|
||||||
(( ! ${+ZSH_AUTOSUGGEST_AI_MIN_INPUT} )) &&
|
(( ! ${+ZSH_AUTOSUGGEST_AI_MIN_INPUT} )) &&
|
||||||
typeset -g ZSH_AUTOSUGGEST_AI_MIN_INPUT=0
|
typeset -g ZSH_AUTOSUGGEST_AI_MIN_INPUT=1
|
||||||
|
|
||||||
# Number of recent history lines to include as context
|
# Number of recent history lines to include as context
|
||||||
(( ! ${+ZSH_AUTOSUGGEST_AI_HISTORY_LINES} )) &&
|
(( ! ${+ZSH_AUTOSUGGEST_AI_HISTORY_LINES} )) &&
|
||||||
typeset -g ZSH_AUTOSUGGEST_AI_HISTORY_LINES=20
|
typeset -g ZSH_AUTOSUGGEST_AI_HISTORY_LINES=5
|
||||||
|
|
||||||
# Prefer history entries from current directory
|
# Prefer history entries from current directory
|
||||||
(( ! ${+ZSH_AUTOSUGGEST_AI_PREFER_PWD_HISTORY} )) &&
|
(( ! ${+ZSH_AUTOSUGGEST_AI_PREFER_PWD_HISTORY} )) &&
|
||||||
typeset -g ZSH_AUTOSUGGEST_AI_PREFER_PWD_HISTORY=yes
|
typeset -g ZSH_AUTOSUGGEST_AI_PREFER_PWD_HISTORY=no
|
||||||
|
|
||||||
# Allow suggestions on empty buffer (opt-in, for AI strategy)
|
# Enable AI debug logs to stderr (opt-in).
|
||||||
# Set to any value to enable. Unset by default.
|
# Set to any value except 0/false/no/off to enable.
|
||||||
# Uses (( ${+VAR} )) pattern like ZSH_AUTOSUGGEST_MANUAL_REBIND
|
|
||||||
|
|
||||||
#--------------------------------------------------------------------#
|
#--------------------------------------------------------------------#
|
||||||
# Utility Functions #
|
# Utility Functions #
|
||||||
|
|
@ -305,8 +305,9 @@ _zsh_autosuggest_disable() {
|
||||||
# Enable suggestions
|
# Enable suggestions
|
||||||
_zsh_autosuggest_enable() {
|
_zsh_autosuggest_enable() {
|
||||||
unset _ZSH_AUTOSUGGEST_DISABLED
|
unset _ZSH_AUTOSUGGEST_DISABLED
|
||||||
|
local min_input="${ZSH_AUTOSUGGEST_AI_MIN_INPUT:-1}"
|
||||||
|
|
||||||
if (( $#BUFFER )) || (( ${+ZSH_AUTOSUGGEST_ALLOW_EMPTY_BUFFER} )); then
|
if (( $#BUFFER )) || (( min_input == 0 )); then
|
||||||
_zsh_autosuggest_fetch
|
_zsh_autosuggest_fetch
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
@ -366,11 +367,12 @@ _zsh_autosuggest_modify() {
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Get a new suggestion if the buffer is not empty after modification
|
# Get a new suggestion if the buffer is not empty after modification
|
||||||
|
local min_input="${ZSH_AUTOSUGGEST_AI_MIN_INPUT:-1}"
|
||||||
if (( $#BUFFER > 0 )); then
|
if (( $#BUFFER > 0 )); then
|
||||||
if [[ -z "$ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE" ]] || (( $#BUFFER <= $ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE )); then
|
if [[ -z "$ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE" ]] || (( $#BUFFER <= $ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE )); then
|
||||||
_zsh_autosuggest_fetch
|
_zsh_autosuggest_fetch
|
||||||
fi
|
fi
|
||||||
elif (( ${+ZSH_AUTOSUGGEST_ALLOW_EMPTY_BUFFER} )); then
|
elif (( min_input == 0 )); then
|
||||||
_zsh_autosuggest_fetch
|
_zsh_autosuggest_fetch
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
@ -393,8 +395,9 @@ _zsh_autosuggest_suggest() {
|
||||||
emulate -L zsh
|
emulate -L zsh
|
||||||
|
|
||||||
local suggestion="$1"
|
local suggestion="$1"
|
||||||
|
local min_input="${ZSH_AUTOSUGGEST_AI_MIN_INPUT:-1}"
|
||||||
|
|
||||||
if [[ -n "$suggestion" ]] && { (( $#BUFFER )) || (( ${+ZSH_AUTOSUGGEST_ALLOW_EMPTY_BUFFER} )); }; then
|
if [[ -n "$suggestion" ]] && { (( $#BUFFER )) || (( min_input == 0 )); }; then
|
||||||
POSTDISPLAY="${suggestion#$BUFFER}"
|
POSTDISPLAY="${suggestion#$BUFFER}"
|
||||||
else
|
else
|
||||||
POSTDISPLAY=
|
POSTDISPLAY=
|
||||||
|
|
@ -561,8 +564,8 @@ _zsh_autosuggest_strategy_ai_gather_context() {
|
||||||
# Reset options to defaults and enable LOCAL_OPTIONS
|
# Reset options to defaults and enable LOCAL_OPTIONS
|
||||||
emulate -L zsh
|
emulate -L zsh
|
||||||
|
|
||||||
local max_lines="${ZSH_AUTOSUGGEST_AI_HISTORY_LINES:-20}"
|
local max_lines="${ZSH_AUTOSUGGEST_AI_HISTORY_LINES:-5}"
|
||||||
local prefer_pwd="${ZSH_AUTOSUGGEST_AI_PREFER_PWD_HISTORY:-yes}"
|
local prefer_pwd="${ZSH_AUTOSUGGEST_AI_PREFER_PWD_HISTORY:-no}"
|
||||||
local pwd_basename="${PWD:t}"
|
local pwd_basename="${PWD:t}"
|
||||||
local -a context_lines
|
local -a context_lines
|
||||||
local -a pwd_lines
|
local -a pwd_lines
|
||||||
|
|
@ -667,6 +670,18 @@ _zsh_autosuggest_strategy_ai_normalize() {
|
||||||
printf '%s' "$result"
|
printf '%s' "$result"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_zsh_autosuggest_strategy_ai_debug_log() {
|
||||||
|
# Reset options to defaults and enable LOCAL_OPTIONS
|
||||||
|
emulate -L zsh
|
||||||
|
|
||||||
|
local debug="${ZSH_AUTOSUGGEST_AI_DEBUG:-0}"
|
||||||
|
case "${debug:l}" in
|
||||||
|
0|false|no|off) return ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
print -ru2 -- "[zsh-autosuggestions ai] $1"
|
||||||
|
}
|
||||||
|
|
||||||
_zsh_autosuggest_strategy_ai() {
|
_zsh_autosuggest_strategy_ai() {
|
||||||
# Reset options to defaults and enable LOCAL_OPTIONS
|
# Reset options to defaults and enable LOCAL_OPTIONS
|
||||||
emulate -L zsh
|
emulate -L zsh
|
||||||
|
|
@ -675,14 +690,23 @@ _zsh_autosuggest_strategy_ai() {
|
||||||
local buffer="$1"
|
local buffer="$1"
|
||||||
|
|
||||||
# Early return if API key not set (opt-in gate)
|
# Early return if API key not set (opt-in gate)
|
||||||
[[ -z "$ZSH_AUTOSUGGEST_AI_API_KEY" ]] && return
|
if [[ -z "$ZSH_AUTOSUGGEST_AI_API_KEY" ]]; then
|
||||||
|
_zsh_autosuggest_strategy_ai_debug_log "API key not set; skipping AI request."
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
# Early return if curl or jq not available
|
# Early return if curl or jq not available
|
||||||
[[ -z "${commands[curl]}" ]] || [[ -z "${commands[jq]}" ]] && return
|
if [[ -z "${commands[curl]}" ]] || [[ -z "${commands[jq]}" ]]; then
|
||||||
|
_zsh_autosuggest_strategy_ai_debug_log "Missing dependency: curl and jq are required."
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
# Early return if input too short
|
# Early return if input too short
|
||||||
local min_input="${ZSH_AUTOSUGGEST_AI_MIN_INPUT:-0}"
|
local min_input="${ZSH_AUTOSUGGEST_AI_MIN_INPUT:-1}"
|
||||||
[[ ${#buffer} -lt $min_input ]] && return
|
if [[ ${#buffer} -lt $min_input ]]; then
|
||||||
|
_zsh_autosuggest_strategy_ai_debug_log "Input shorter than ZSH_AUTOSUGGEST_AI_MIN_INPUT=$min_input."
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
# Gather history context
|
# Gather history context
|
||||||
local -a context
|
local -a context
|
||||||
|
|
@ -748,6 +772,8 @@ _zsh_autosuggest_strategy_ai() {
|
||||||
local timeout="${ZSH_AUTOSUGGEST_AI_TIMEOUT:-5}"
|
local timeout="${ZSH_AUTOSUGGEST_AI_TIMEOUT:-5}"
|
||||||
local response
|
local response
|
||||||
|
|
||||||
|
_zsh_autosuggest_strategy_ai_debug_log "Requesting $endpoint (model=${ZSH_AUTOSUGGEST_AI_MODEL:-gpt-3.5-turbo}, input_len=${#buffer})."
|
||||||
|
|
||||||
response=$(curl --silent --max-time "$timeout" \
|
response=$(curl --silent --max-time "$timeout" \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
-H "Authorization: Bearer $ZSH_AUTOSUGGEST_AI_API_KEY" \
|
-H "Authorization: Bearer $ZSH_AUTOSUGGEST_AI_API_KEY" \
|
||||||
|
|
@ -756,28 +782,41 @@ _zsh_autosuggest_strategy_ai() {
|
||||||
"$endpoint" 2>/dev/null)
|
"$endpoint" 2>/dev/null)
|
||||||
|
|
||||||
# Check curl exit status
|
# Check curl exit status
|
||||||
[[ $? -ne 0 ]] && return
|
local curl_status=$?
|
||||||
|
if [[ $curl_status -ne 0 ]]; then
|
||||||
|
_zsh_autosuggest_strategy_ai_debug_log "curl failed with exit code $curl_status."
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
# Split response body from HTTP status
|
# Split response body from HTTP status
|
||||||
local http_code="${response##*$'\n'}"
|
local http_code="${response##*$'\n'}"
|
||||||
local body="${response%$'\n'*}"
|
local body="${response%$'\n'*}"
|
||||||
|
|
||||||
# Early return on non-2xx status
|
# Early return on non-2xx status
|
||||||
[[ "$http_code" != 2* ]] && return
|
if [[ "$http_code" != 2* ]]; then
|
||||||
|
_zsh_autosuggest_strategy_ai_debug_log "HTTP $http_code from AI endpoint."
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
# Extract content from JSON response
|
# Extract content from JSON response
|
||||||
local content
|
local content
|
||||||
content=$(printf '%s' "$body" | jq -r '.choices[0].message.content // empty' 2>/dev/null)
|
content=$(printf '%s' "$body" | jq -r '.choices[0].message.content // empty' 2>/dev/null)
|
||||||
|
|
||||||
# Early return if extraction failed
|
# Early return if extraction failed
|
||||||
[[ -z "$content" ]] && return
|
if [[ -z "$content" ]]; then
|
||||||
|
_zsh_autosuggest_strategy_ai_debug_log "No suggestion content in API response."
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
# Normalize response
|
# Normalize response
|
||||||
local normalized
|
local normalized
|
||||||
normalized="$(_zsh_autosuggest_strategy_ai_normalize "$content" "$buffer")"
|
normalized="$(_zsh_autosuggest_strategy_ai_normalize "$content" "$buffer")"
|
||||||
|
|
||||||
# Set suggestion
|
# Set suggestion
|
||||||
[[ -n "$normalized" ]] && suggestion="$normalized"
|
if [[ -n "$normalized" ]]; then
|
||||||
|
suggestion="$normalized"
|
||||||
|
_zsh_autosuggest_strategy_ai_debug_log "AI suggestion accepted: '$normalized'."
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
#--------------------------------------------------------------------#
|
#--------------------------------------------------------------------#
|
||||||
|
|
@ -1154,7 +1193,8 @@ add-zsh-hook precmd _zsh_autosuggest_start
|
||||||
|
|
||||||
_zsh_autosuggest_line_init() {
|
_zsh_autosuggest_line_init() {
|
||||||
emulate -L zsh
|
emulate -L zsh
|
||||||
if (( ${+ZSH_AUTOSUGGEST_ALLOW_EMPTY_BUFFER} )) && \
|
local min_input="${ZSH_AUTOSUGGEST_AI_MIN_INPUT:-1}"
|
||||||
|
if (( min_input == 0 )) && \
|
||||||
(( ! ${+_ZSH_AUTOSUGGEST_DISABLED} )); then
|
(( ! ${+_ZSH_AUTOSUGGEST_DISABLED} )); then
|
||||||
_zsh_autosuggest_fetch
|
_zsh_autosuggest_fetch
|
||||||
fi
|
fi
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue