@ia-ccun/code-agent-cli 0.0.52 → 0.0.53-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/cli.js +97 -69
- package/config/agent/bin/README.md +102 -0
- package/config/agent/extensions/aicode-advisor.ts +197 -61
- package/config/agent/extensions/aicode-banner.ts +101 -0
- package/config/agent/extensions/aicode-btw.ts +677 -183
- package/config/agent/extensions/aicode-cd.ts +1017 -0
- package/config/agent/extensions/aicode-grillMe.ts +198 -0
- package/config/agent/extensions/aicode-pets.ts +351 -0
- package/config/agent/extensions/aicode-plan.ts +2 -0
- package/config/agent/extensions/aicode-safety-guard.ts +555 -0
- package/config/agent/extensions/aicode-tips.ts +69 -30
- package/config/agent/extensions/aicode-todo-progress.ts +547 -0
- package/config/agent/extensions/context-monitor.ts +30 -15
- package/config/agent/extensions/context.ts +132 -60
- package/config/agent/extensions/custom-footer.ts +0 -5
- package/config/agent/extensions/custom.ts +119 -109
- package/config/agent/extensions/error-monitor.ts +38 -51
- package/config/agent/extensions/goal.ts +8 -6
- package/config/agent/extensions/msg-debug.ts +103 -112
- package/config/agent/extensions/ponytail.ts +441 -0
- package/config/agent/extensions/review.ts +365 -164
- package/config/agent/extensions/tps.ts +87 -0
- package/config/agent/extensions/working-msg.ts +164 -51
- package/config/agent/help.md +0 -7
- package/config/agent/models.json +7 -7
- package/config/agent/settings.json +2 -1
- package/config/agent/skills/chroma/LICENSE +21 -0
- package/config/agent/skills/chroma/chroma-local/SKILL.md +165 -0
- package/config/agent/skills/chroma/chroma-local/cli.md +48 -0
- package/config/agent/skills/chroma/chroma-local/data-model.md +103 -0
- package/config/agent/skills/chroma/chroma-local/error-handling/python.md +166 -0
- package/config/agent/skills/chroma/chroma-local/error-handling/typescript.md +231 -0
- package/config/agent/skills/chroma/chroma-local/local-chroma/python.md +95 -0
- package/config/agent/skills/chroma/chroma-local/local-chroma/typescript.md +101 -0
- package/config/agent/skills/chroma/chroma-local/metadata/python.md +154 -0
- package/config/agent/skills/chroma/chroma-local/metadata/typescript.md +153 -0
- package/config/agent/skills/chroma/chroma-local/querying/python.md +147 -0
- package/config/agent/skills/chroma/chroma-local/querying/typescript.md +157 -0
- package/config/agent/skills/chroma/chroma-local/regex/python.md +69 -0
- package/config/agent/skills/chroma/chroma-local/regex/typescript.md +71 -0
- package/config/agent/skills/chroma/chroma-local/understanding-a-codebase.md +80 -0
- package/config/agent/skills/chroma/chroma-local/updating-deleting/python.md +159 -0
- package/config/agent/skills/chroma/chroma-local/updating-deleting/typescript.md +228 -0
- package/config/agent/skills/milvus-skill/LICENSE +202 -0
- package/config/agent/skills/milvus-skill/README.md +37 -0
- package/config/agent/skills/milvus-skill/SKILL.md +259 -0
- package/config/agent/skills/milvus-skill/references/collection.md +86 -0
- package/config/agent/skills/milvus-skill/references/database.md +24 -0
- package/config/agent/skills/milvus-skill/references/index.md +69 -0
- package/config/agent/skills/milvus-skill/references/partition.md +29 -0
- package/config/agent/skills/milvus-skill/references/patterns.md +150 -0
- package/config/agent/skills/milvus-skill/references/user-role.md +90 -0
- package/config/agent/skills/milvus-skill/references/vector.md +247 -0
- package/config/agent/skills/ponytail/SKILL.md +100 -0
- package/config/agent/skills/ponytail-audit/SKILL.md +40 -0
- package/config/agent/skills/ponytail-debt/SKILL.md +44 -0
- package/config/agent/skills/ponytail-help/SKILL.md +68 -0
- package/config/agent/skills/ponytail-review/SKILL.md +56 -0
- package/config/agent/skills/zread/README.md +115 -0
- package/config/agent/skills/zread/SKILL.md +103 -0
- package/config/agent/skills/zread/references/stdio-protocol.md +312 -0
- package/dist/banner.d.ts.map +1 -1
- package/dist/banner.js +8 -1
- package/dist/banner.js.map +1 -1
- package/dist/config-loader.d.ts.map +1 -1
- package/dist/config-loader.js +9 -2
- package/dist/config-loader.js.map +1 -1
- package/package.json +7 -7
- package/scripts/postinstall.js +58 -1
- package/scripts/regression/README.md +224 -0
- package/scripts/regression/cases/01-version-and-deps.sh +94 -0
- package/scripts/regression/cases/02-extension-loading.sh +130 -0
- package/scripts/regression/cases/03-rpc-protocol.sh +259 -0
- package/scripts/regression/cases/04-prompt-stream.sh +130 -0
- package/scripts/regression/cases/05-slash-commands-and-skills.sh +119 -0
- package/scripts/regression/cases/06-tool-execution.sh +115 -0
- package/scripts/regression/cases/07-pi-new-features.sh +141 -0
- package/scripts/regression/lib/common.sh +287 -0
- package/scripts/regression/results/.last_pid +1 -0
- package/scripts/regression/results/.last_workdir +1 -0
- package/scripts/regression/results/02-extension-loading.log +18 -0
- package/scripts/regression/results/03-prompt-stream.log +16 -0
- package/scripts/regression/results/03-rpc-protocol.log +27 -0
- package/scripts/regression/results/04-slash-commands-and-skills.log +11 -0
- package/scripts/regression/results/05-tool-execution.log +8 -0
- package/scripts/regression/results/06-pi-new-features.log +29 -0
- package/scripts/regression/run-all.sh +187 -0
- package/config/agent/dangerous-patterns.json +0 -106
- package/config/agent/extensions/bash-check.ts +0 -227
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# 06-pi-new-features.sh
|
|
3
|
+
# 验证:pi 0.85+ 新功能在 aicode 端可用
|
|
4
|
+
#
|
|
5
|
+
# 重点:
|
|
6
|
+
# - clear_queue RPC(0.84.4+ 新增)
|
|
7
|
+
# - GPT-6 Astra 是否出现在 available_models
|
|
8
|
+
# - thinking 持久化(set_thinking_level 后 turn 间不丢)
|
|
9
|
+
# - usage.cacheWrite1h 字段(0.85+ 新增)
|
|
10
|
+
# - 持久化 Claude thinking effort(0.85+)
|
|
11
|
+
# - /thinking 命令选择器(0.84.3+)
|
|
12
|
+
|
|
13
|
+
set -uo pipefail
|
|
14
|
+
CURRENT_CASE="06-pi-new-features"
|
|
15
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
16
|
+
source "$SCRIPT_DIR/../lib/common.sh"
|
|
17
|
+
|
|
18
|
+
header "$CURRENT_CASE" "pi 0.85+ new features"
|
|
19
|
+
|
|
20
|
+
if ! spawn_rpc 90; then
|
|
21
|
+
fail "spawn aicode RPC" "进程启动失败"
|
|
22
|
+
summary
|
|
23
|
+
exit 1
|
|
24
|
+
fi
|
|
25
|
+
pass "spawn aicode RPC (pid=$REGRESSION_PID)"
|
|
26
|
+
|
|
27
|
+
# ----- Test 1: clear_queue RPC -----
|
|
28
|
+
header "$CURRENT_CASE" "clear_queue RPC (0.84.4+)"
|
|
29
|
+
|
|
30
|
+
send '{"type":"clear_queue","id":"n1"}'
|
|
31
|
+
sleep 0.5
|
|
32
|
+
|
|
33
|
+
if jq -e 'select(.id=="n1" and .type=="response" and .success==true)' "$REGRESSION_LOG" >/dev/null 2>&1; then
|
|
34
|
+
pass "clear_queue RPC 成功"
|
|
35
|
+
|
|
36
|
+
# 验证返回结构
|
|
37
|
+
if jq -e 'select(.id=="n1" and .type=="response") | .data | has("steering") and has("followUp")' "$REGRESSION_LOG" >/dev/null 2>&1; then
|
|
38
|
+
pass "clear_queue 返回 {steering,followUp} 字段"
|
|
39
|
+
else
|
|
40
|
+
skip "clear_queue 返回 {steering,followUp} 字段" "字段名可能不同(followUps/follow_ups)"
|
|
41
|
+
fi
|
|
42
|
+
else
|
|
43
|
+
err=$(jq -c 'select(.id=="n1" and .type=="response") | .error // ""' "$REGRESSION_LOG" 2>/dev/null | head -1)
|
|
44
|
+
if [[ -n "$err" && "$err" != '""' ]]; then
|
|
45
|
+
skip "clear_queue RPC" "pi < 0.84.4 不支持: $err"
|
|
46
|
+
else
|
|
47
|
+
fail "clear_queue RPC" "无 response"
|
|
48
|
+
fi
|
|
49
|
+
fi
|
|
50
|
+
|
|
51
|
+
# ----- Test 2: GPT-6 Astra 在 available_models -----
|
|
52
|
+
header "$CURRENT_CASE" "GPT-6 Astra (0.85.0+)"
|
|
53
|
+
|
|
54
|
+
send '{"type":"get_available_models","id":"n2"}'
|
|
55
|
+
sleep 1
|
|
56
|
+
|
|
57
|
+
models=$(jq -c 'select(.id=="n2" and .type=="response") | .data' "$REGRESSION_LOG" 2>/dev/null | head -1)
|
|
58
|
+
if [[ -n "$models" ]]; then
|
|
59
|
+
if echo "$models" | jq -e '.[] | select(.id | tostring | contains("gpt-6"))' >/dev/null 2>&1; then
|
|
60
|
+
pass "GPT-6 系列模型在 catalog 中"
|
|
61
|
+
gpt6=$(echo "$models" | jq -r '.[] | select(.id | tostring | contains("gpt-6")) | .id' 2>/dev/null | head -3)
|
|
62
|
+
echo " 发现: $(echo "$gpt6" | tr '\n' ' ')"
|
|
63
|
+
else
|
|
64
|
+
skip "GPT-6 Astra 在 catalog 中" "未找到 gpt-6* 模型(取决于 provider 配置)"
|
|
65
|
+
fi
|
|
66
|
+
else
|
|
67
|
+
fail "get_available_models 返回 data" "无响应"
|
|
68
|
+
fi
|
|
69
|
+
|
|
70
|
+
# ----- Test 3: set_thinking_level + 持久化(0.85.0)-----
|
|
71
|
+
header "$CURRENT_CASE" "thinking level persistence (0.85.0)"
|
|
72
|
+
|
|
73
|
+
# 设置 high
|
|
74
|
+
send '{"type":"set_thinking_level","level":"high","id":"n3a"}'
|
|
75
|
+
sleep 0.5
|
|
76
|
+
if jq -e 'select(.id=="n3a" and .type=="response" and .success==true)' "$REGRESSION_LOG" >/dev/null 2>&1; then
|
|
77
|
+
pass "set_thinking_level high 成功"
|
|
78
|
+
else
|
|
79
|
+
fail "set_thinking_level high" "无响应"
|
|
80
|
+
fi
|
|
81
|
+
|
|
82
|
+
# 再发一个 prompt 让它跑
|
|
83
|
+
send '{"type":"prompt","message":"say hi","id":"n3b"}'
|
|
84
|
+
sleep 8
|
|
85
|
+
|
|
86
|
+
# 等 prompt 完成
|
|
87
|
+
waited=0
|
|
88
|
+
while [[ $waited -lt 60 ]]; do
|
|
89
|
+
if jq -e 'select(.id=="n3b" and .type=="response")' "$REGRESSION_LOG" >/dev/null 2>&1; then
|
|
90
|
+
break
|
|
91
|
+
fi
|
|
92
|
+
sleep 1
|
|
93
|
+
waited=$((waited + 1))
|
|
94
|
+
done
|
|
95
|
+
|
|
96
|
+
# 查询 get_state — thinking level 应该还是 high
|
|
97
|
+
send '{"type":"get_state","id":"n3c"}'
|
|
98
|
+
sleep 0.5
|
|
99
|
+
|
|
100
|
+
state_level=$(jq -c 'select(.id=="n3c" and .type=="response") | .data.thinkingLevel // "missing"' "$REGRESSION_LOG" 2>/dev/null | head -1)
|
|
101
|
+
if [[ "$state_level" == '"high"' ]]; then
|
|
102
|
+
pass "thinking level 在 turn 间保持 high(持久化)"
|
|
103
|
+
else
|
|
104
|
+
if [[ "$state_level" == '"medium"' ]]; then
|
|
105
|
+
skip "thinking level 持久化" "回到 medium(0.85 之前行为)"
|
|
106
|
+
else
|
|
107
|
+
fail "thinking level 持久化" "got: $state_level"
|
|
108
|
+
fi
|
|
109
|
+
fi
|
|
110
|
+
|
|
111
|
+
# ----- Test 4: usage.cacheWrite1h 字段(0.85.0+)-----
|
|
112
|
+
header "$CURRENT_CASE" "usage.cacheWrite1h field (0.85.0+)"
|
|
113
|
+
|
|
114
|
+
# 看 turn_end 事件的 usage 是否包含 cacheWrite1h
|
|
115
|
+
has_cw1h=$(jq -c 'select(.type=="turn_end") | .message.usage | has("cacheWrite1h")' "$REGRESSION_LOG" 2>/dev/null | head -1)
|
|
116
|
+
if [[ "$has_cw1h" == "true" ]]; then
|
|
117
|
+
pass "turn_end.usage.cacheWrite1h 字段存在"
|
|
118
|
+
else
|
|
119
|
+
skip "turn_end.usage.cacheWrite1h 字段" "不存在(pi < 0.85.0 或 provider 不报告)"
|
|
120
|
+
fi
|
|
121
|
+
|
|
122
|
+
# ----- Test 5: get_available_thinking_levels -----
|
|
123
|
+
header "$CURRENT_CASE" "thinking levels list"
|
|
124
|
+
|
|
125
|
+
send '{"type":"get_available_thinking_levels","id":"n5"}'
|
|
126
|
+
sleep 0.5
|
|
127
|
+
|
|
128
|
+
if jq -e 'select(.id=="n5" and .type=="response" and .success==true)' "$REGRESSION_LOG" >/dev/null 2>&1; then
|
|
129
|
+
levels=$(jq -c 'select(.id=="n5" and .type=="response") | .data | length' "$REGRESSION_LOG" 2>/dev/null | head -1)
|
|
130
|
+
if [[ -n "$levels" && "$levels" -gt 0 ]]; then
|
|
131
|
+
pass "get_available_thinking_levels 返回 $levels 个级别"
|
|
132
|
+
else
|
|
133
|
+
fail "thinking levels 非空" "got: $levels"
|
|
134
|
+
fi
|
|
135
|
+
else
|
|
136
|
+
fail "get_available_thinking_levels" "无响应"
|
|
137
|
+
fi
|
|
138
|
+
|
|
139
|
+
cleanup_rpc
|
|
140
|
+
summary
|
|
141
|
+
exit $?
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# common.sh - 回归测试公共工具
|
|
3
|
+
# 用法:在 case 脚本开头 source "$(dirname "${BASH_SOURCE[0]}")/lib/common.sh"
|
|
4
|
+
|
|
5
|
+
# 严格模式:未定义变量报错,但允许管道部分失败(grep 找不到时 exit 1)
|
|
6
|
+
set -uo pipefail
|
|
7
|
+
|
|
8
|
+
# 默认配置
|
|
9
|
+
: "${AICODE_BIN:=aicode}" # aicode 二进制路径
|
|
10
|
+
: "${AICODE_CONFIG:=$HOME/.aicode-cli}" # 配置目录
|
|
11
|
+
: "${AICODE_TIMEOUT:=30}" # RPC 测试默认超时(秒)
|
|
12
|
+
: "${REGRESSION_QUIET:=0}" # 1 = 减少输出
|
|
13
|
+
|
|
14
|
+
# 路径
|
|
15
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
16
|
+
RESULTS_DIR="$SCRIPT_DIR/results"
|
|
17
|
+
mkdir -p "$RESULTS_DIR"
|
|
18
|
+
|
|
19
|
+
# 颜色(仅 TTY 启用)
|
|
20
|
+
if [[ -t 1 ]] && [[ "${REGRESSION_QUIET:-0}" != "1" ]]; then
|
|
21
|
+
RED=$'\033[0;31m'; GREEN=$'\033[0;32m'; YELLOW=$'\033[0;33m'; BLUE=$'\033[0;34m'; CYAN=$'\033[0;36m'; DIM=$'\033[2m'; NC=$'\033[0m'
|
|
22
|
+
else
|
|
23
|
+
RED=''; GREEN=''; YELLOW=''; BLUE=''; CYAN=''; DIM=''; NC=''
|
|
24
|
+
fi
|
|
25
|
+
|
|
26
|
+
# 计数器
|
|
27
|
+
PASS_COUNT=0
|
|
28
|
+
FAIL_COUNT=0
|
|
29
|
+
SKIP_COUNT=0
|
|
30
|
+
CURRENT_CASE="${CURRENT_CASE:-$(basename "${BASH_SOURCE[1]:-unknown}" .sh)}"
|
|
31
|
+
|
|
32
|
+
# ----- 输出 -----
|
|
33
|
+
header() {
|
|
34
|
+
[[ "${REGRESSION_QUIET:-0}" == "1" ]] && return
|
|
35
|
+
echo ""
|
|
36
|
+
echo "${CYAN}─── $CURRENT_CASE: $2 ───${NC}"
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
pass() {
|
|
40
|
+
local name="$1"
|
|
41
|
+
echo " ${GREEN}✓${NC} $name"
|
|
42
|
+
PASS_COUNT=$((PASS_COUNT + 1))
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
fail() {
|
|
46
|
+
local name="$1"
|
|
47
|
+
local reason="${2:-no reason}"
|
|
48
|
+
echo " ${RED}✗${NC} $name"
|
|
49
|
+
echo " ${DIM}└─ $reason${NC}"
|
|
50
|
+
FAIL_COUNT=$((FAIL_COUNT + 1))
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
skip() {
|
|
54
|
+
local name="$1"
|
|
55
|
+
local reason="${2:-no reason}"
|
|
56
|
+
echo " ${YELLOW}○${NC} $name ${DIM}(skipped: $reason)${NC}"
|
|
57
|
+
SKIP_COUNT=$((SKIP_COUNT + 1))
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
summary() {
|
|
61
|
+
local exit_code=0
|
|
62
|
+
echo ""
|
|
63
|
+
if [[ $FAIL_COUNT -eq 0 && $SKIP_COUNT -eq 0 ]]; then
|
|
64
|
+
echo "${GREEN}✓ $CURRENT_CASE: ALL PASS${NC} ${DIM}($PASS_COUNT checks)${NC}"
|
|
65
|
+
elif [[ $FAIL_COUNT -eq 0 ]]; then
|
|
66
|
+
echo "${YELLOW}△ $CURRENT_CASE: PASS with skips${NC} ${DIM}($PASS_COUNT pass, $SKIP_COUNT skip)${NC}"
|
|
67
|
+
else
|
|
68
|
+
echo "${RED}✗ $CURRENT_CASE: FAILED${NC} ${DIM}($FAIL_COUNT fail, $PASS_COUNT pass, $SKIP_COUNT skip)${NC}"
|
|
69
|
+
exit_code=1
|
|
70
|
+
fi
|
|
71
|
+
return $exit_code
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
# ----- RPC 进程管理 -----
|
|
75
|
+
#
|
|
76
|
+
# spawn_rpc [timeout_seconds]
|
|
77
|
+
# 启动 aicode -ne --mode rpc --no-session,stdin 从 fd 11 读,stdout/stderr 到 fd 12 写
|
|
78
|
+
# 用法见 cases/02-rpc-handshake.sh
|
|
79
|
+
#
|
|
80
|
+
spawn_rpc() {
|
|
81
|
+
local timeout="${1:-$AICODE_TIMEOUT}"
|
|
82
|
+
local skip_extensions="${2:-true}"
|
|
83
|
+
|
|
84
|
+
if ! command -v "$AICODE_BIN" >/dev/null 2>&1; then
|
|
85
|
+
echo "ERROR: $AICODE_BIN not found. Set AICODE_BIN env var to override." >&2
|
|
86
|
+
return 127
|
|
87
|
+
fi
|
|
88
|
+
|
|
89
|
+
# 临时配置必须在 $HOME 下,aicode-cli 的 config-loader.ts 安全检查
|
|
90
|
+
# 会拒绝非 home 目录并回退到 ~/.aicode-cli
|
|
91
|
+
# 用 home 下的隐藏目录避免污染用户配置
|
|
92
|
+
local workdir="$HOME/.aicode-regression-$$-$(date +%s%N | tail -c 8)"
|
|
93
|
+
mkdir -p "$workdir/agent/extensions"
|
|
94
|
+
local cfg="$workdir/config.json"
|
|
95
|
+
cat >"$cfg" <<EOF
|
|
96
|
+
{
|
|
97
|
+
"name": "aicode-regression",
|
|
98
|
+
"banner": "",
|
|
99
|
+
"themeColor": "#49bccf",
|
|
100
|
+
"configDir": "$(basename "$workdir")"
|
|
101
|
+
}
|
|
102
|
+
EOF
|
|
103
|
+
|
|
104
|
+
# 复用用户全局的 auth.json / models.json / settings.json + prompts / skills / extensions
|
|
105
|
+
# (避免重新登录/配置,且能让 pi 加载预置 prompts 和 skills)
|
|
106
|
+
# ~/.pi 通常是 ~/.aicode-cli 的 symlink
|
|
107
|
+
local user_agent_dir="$HOME/.aicode-cli/agent"
|
|
108
|
+
if [[ -d "$user_agent_dir" ]]; then
|
|
109
|
+
for f in auth.json models.json settings.json; do
|
|
110
|
+
[[ -f "$user_agent_dir/$f" ]] && cp "$user_agent_dir/$f" "$workdir/agent/$f" 2>/dev/null
|
|
111
|
+
done
|
|
112
|
+
# 复制 prompts/skills/extensions 目录(不覆盖本地)
|
|
113
|
+
for d in prompts skills extensions themes; do
|
|
114
|
+
if [[ -d "$user_agent_dir/$d" ]]; then
|
|
115
|
+
cp -R "$user_agent_dir/$d" "$workdir/agent/" 2>/dev/null
|
|
116
|
+
fi
|
|
117
|
+
done
|
|
118
|
+
fi
|
|
119
|
+
|
|
120
|
+
# 覆盖 provider(如果设置了 AICODE_REGRESSION_PROVIDER_*)
|
|
121
|
+
# 用于跨供应商测试:minimax / siliconflow-anthropic / siliconflow-openai 等
|
|
122
|
+
if [[ -n "${AICODE_REGRESSION_BASE_URL:-}" ]] && [[ -n "${AICODE_REGRESSION_API_KEY:-}" ]]; then
|
|
123
|
+
# 在 models.json 里加一个 anthropic 兼容 provider
|
|
124
|
+
local api_kind="${AICODE_REGRESSION_API_KIND:-anthropic-messages}"
|
|
125
|
+
local provider_id="${AICODE_REGRESSION_PROVIDER_ID:-regression}"
|
|
126
|
+
local model_id="${AICODE_REGRESSION_MODEL_ID:-claude-sonnet-4-5}"
|
|
127
|
+
python3 -c "
|
|
128
|
+
import json
|
|
129
|
+
p = '$workdir/agent/models.json'
|
|
130
|
+
try:
|
|
131
|
+
d = json.load(open(p))
|
|
132
|
+
except: d = {'providers': {}}
|
|
133
|
+
prov = d.setdefault('providers', {})
|
|
134
|
+
prov['$provider_id'] = {
|
|
135
|
+
'baseUrl': '$AICODE_REGRESSION_BASE_URL',
|
|
136
|
+
'apiKey': '$AICODE_REGRESSION_API_KEY',
|
|
137
|
+
'api': '$api_kind',
|
|
138
|
+
'models': [
|
|
139
|
+
{'id': '$model_id', 'name': '$model_id', 'contextWindow': 128000, 'maxTokens': 16384}
|
|
140
|
+
]
|
|
141
|
+
}
|
|
142
|
+
json.dump(d, open(p, 'w'), indent=2)
|
|
143
|
+
" 2>/dev/null
|
|
144
|
+
|
|
145
|
+
# 修改 settings.json 的 defaultProvider
|
|
146
|
+
[[ -f "$workdir/agent/settings.json" ]] && python3 -c "
|
|
147
|
+
import json
|
|
148
|
+
p = '$workdir/agent/settings.json'
|
|
149
|
+
try:
|
|
150
|
+
d = json.load(open(p))
|
|
151
|
+
except: d = {}
|
|
152
|
+
d['defaultProvider'] = '$provider_id'
|
|
153
|
+
d['defaultModel'] = '$model_id'
|
|
154
|
+
json.dump(d, open(p, 'w'), indent=2)
|
|
155
|
+
" 2>/dev/null
|
|
156
|
+
fi
|
|
157
|
+
|
|
158
|
+
# 创建 stdin fifo(aicode 需要从 stdin 持续读取 RPC 命令)
|
|
159
|
+
mkfifo "$workdir/stdin.fifo" 2>/dev/null || true
|
|
160
|
+
|
|
161
|
+
# fd 11 = stdin (case 脚本可以 printf 到 &11)
|
|
162
|
+
# fd 12 = stdout+stderr 合并的 log(用于后续分析)
|
|
163
|
+
exec 11<>"$workdir/stdin.fifo"
|
|
164
|
+
exec 12>"$workdir/output.log"
|
|
165
|
+
|
|
166
|
+
# spawn 进程(默认 -ne 跳过扩展避免 conflict;要加载扩展传 false)
|
|
167
|
+
local ext_flag=""
|
|
168
|
+
if [[ "$skip_extensions" == "true" ]]; then
|
|
169
|
+
ext_flag="-ne"
|
|
170
|
+
fi
|
|
171
|
+
|
|
172
|
+
"$AICODE_BIN" $ext_flag --config "$workdir" --mode rpc --no-session \
|
|
173
|
+
<&11 >&12 2>&1 &
|
|
174
|
+
local pid=$!
|
|
175
|
+
|
|
176
|
+
echo "$workdir" > "$RESULTS_DIR/.last_workdir"
|
|
177
|
+
echo "$pid" > "$RESULTS_DIR/.last_pid"
|
|
178
|
+
|
|
179
|
+
# 主动发一个 get_state 触发首个 response,验证 RPC 通道已就绪
|
|
180
|
+
printf '{"type":"get_state","id":"ready_probe"}\n' >&11
|
|
181
|
+
|
|
182
|
+
# 等待 response 出现(最多 5 秒)
|
|
183
|
+
local ready=0
|
|
184
|
+
for _ in $(seq 1 50); do
|
|
185
|
+
if grep -q '"id":"ready_probe"' "$workdir/output.log" 2>/dev/null; then
|
|
186
|
+
ready=1; break
|
|
187
|
+
fi
|
|
188
|
+
sleep 0.1
|
|
189
|
+
done
|
|
190
|
+
|
|
191
|
+
if [[ $ready -ne 1 ]]; then
|
|
192
|
+
kill "$pid" 2>/dev/null
|
|
193
|
+
echo "ERROR: aicode RPC 启动超时(未收到 ready_probe 响应)" >&2
|
|
194
|
+
echo " log 前 20 行:$(head -20 "$workdir/output.log" 2>/dev/null | tr '\n' '|' | head -c 300)" >&2
|
|
195
|
+
return 1
|
|
196
|
+
fi
|
|
197
|
+
|
|
198
|
+
REGRESSION_PID="$pid"
|
|
199
|
+
REGRESSION_WORKDIR="$workdir"
|
|
200
|
+
REGRESSION_LOG="$workdir/output.log"
|
|
201
|
+
return 0
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
send() {
|
|
205
|
+
# send <json>
|
|
206
|
+
printf '%s\n' "$1" >&11
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
wait_for() {
|
|
210
|
+
# wait_for <jq-filter> [timeout_seconds]
|
|
211
|
+
local filter="$1"
|
|
212
|
+
local timeout="${2:-$AICODE_TIMEOUT}"
|
|
213
|
+
local jqbin="${JQBIN:-jq}"
|
|
214
|
+
|
|
215
|
+
if ! command -v "$jqbin" >/dev/null 2>&1; then
|
|
216
|
+
echo "ERROR: jq not found. brew install jq" >&2
|
|
217
|
+
return 127
|
|
218
|
+
fi
|
|
219
|
+
|
|
220
|
+
# 等到匹配事件出现
|
|
221
|
+
"$jqbin" -c "$filter" "$REGRESSION_LOG" 2>/dev/null | head -1
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
cleanup_rpc() {
|
|
225
|
+
# 关掉 stdin pipe + 杀进程 + 保留 log
|
|
226
|
+
[[ -n "${REGRESSION_PID:-}" ]] && kill "$REGRESSION_PID" 2>/dev/null
|
|
227
|
+
exec 11<&- 2>/dev/null
|
|
228
|
+
exec 12<&- 2>/dev/null
|
|
229
|
+
|
|
230
|
+
if [[ -n "${REGRESSION_LOG:-}" ]] && [[ -f "$REGRESSION_LOG" ]]; then
|
|
231
|
+
cp "$REGRESSION_LOG" "$RESULTS_DIR/${CURRENT_CASE}.log" 2>/dev/null
|
|
232
|
+
fi
|
|
233
|
+
[[ -n "${REGRESSION_WORKDIR:-}" ]] && rm -rf "$REGRESSION_WORKDIR" 2>/dev/null
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
trap_cleanup() {
|
|
237
|
+
cleanup_rpc
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
# ----- 断言辅助 -----
|
|
241
|
+
|
|
242
|
+
assert_eq() {
|
|
243
|
+
# assert_eq <name> <expected> <actual>
|
|
244
|
+
local name="$1" expected="$2" actual="$3"
|
|
245
|
+
if [[ "$expected" == "$actual" ]]; then
|
|
246
|
+
pass "$name"
|
|
247
|
+
else
|
|
248
|
+
fail "$name" "expected: $expected | got: $actual"
|
|
249
|
+
fi
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
assert_contains() {
|
|
253
|
+
# assert_contains <name> <substring> <haystack>
|
|
254
|
+
local name="$1" needle="$2" hay="$3"
|
|
255
|
+
if [[ "$hay" == *"$needle"* ]]; then
|
|
256
|
+
pass "$name"
|
|
257
|
+
else
|
|
258
|
+
fail "$name" "expected to contain: $needle | got: ${hay:0:200}"
|
|
259
|
+
fi
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
assert_event_field() {
|
|
263
|
+
# assert_event_field <name> <jq-filter> <field-equals-value>
|
|
264
|
+
# 例:assert_event_field "model 是 anthropic" 'select(.type=="message_start")' '.message.api' "anthropic-messages"
|
|
265
|
+
local name="$1" event_filter="$2" field="$3" expected="$4"
|
|
266
|
+
local jqbin="${JQBIN:-jq}"
|
|
267
|
+
local actual
|
|
268
|
+
actual=$("$jqbin" -c "$event_filter | $field // \"\"" "$REGRESSION_LOG" 2>/dev/null | head -1)
|
|
269
|
+
if [[ "$actual" == *"\"$expected\""* ]] || [[ "$actual" == "\"$expected\"" ]]; then
|
|
270
|
+
pass "$name"
|
|
271
|
+
else
|
|
272
|
+
fail "$name" "expected $field == '$expected' | got: $actual"
|
|
273
|
+
fi
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
assert_event_count() {
|
|
277
|
+
# assert_event_count <name> <jq-filter> <min-count>
|
|
278
|
+
local name="$1" filter="$2" min="$3"
|
|
279
|
+
local jqbin="${JQBIN:-jq}"
|
|
280
|
+
local count
|
|
281
|
+
count=$("$jqbin" -c "$filter" "$REGRESSION_LOG" 2>/dev/null | wc -l | tr -d ' ')
|
|
282
|
+
if [[ $count -ge $min ]]; then
|
|
283
|
+
pass "$name ($count ≥ $min)"
|
|
284
|
+
else
|
|
285
|
+
fail "$name" "expected ≥ $min matches | got: $count"
|
|
286
|
+
fi
|
|
287
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
85916
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/Users/jianjiang/.aicode-regression-85892-3270000
|