@team-agent/installer 0.5.106 → 0.5.108
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/Cargo.lock +1 -1
- package/Cargo.toml +1 -1
- package/crates/team-agent/src/cli/adapters.rs +1 -1
- package/crates/team-agent/src/cli/emit.rs +3 -3
- package/crates/team-agent/src/cli/mod.rs +87 -4
- package/crates/team-agent/src/cli/models.rs +252 -3
- package/crates/team-agent/src/cli/spec.rs +1 -1
- package/crates/team-agent/src/cli/status_port/brief.rs +155 -37
- package/crates/team-agent/src/cli/tests/base.rs +112 -225
- package/crates/team-agent/src/cli/tests/shutdown_kill_plan.rs +184 -0
- package/crates/team-agent/src/cli/tests/status_brief.rs +624 -0
- package/crates/team-agent/src/compiler/tests.rs +46 -59
- package/crates/team-agent/src/leader/tests/byte_findings.rs +1 -14
- package/crates/team-agent/src/lifecycle/launch/pi_mcp.rs +57 -173
- package/crates/team-agent/src/lifecycle/launch/pi_mcp_extension.js +226 -0
- package/crates/team-agent/src/lifecycle/launch/quick_start.rs +0 -37
- package/crates/team-agent/src/lifecycle/tests/agent_ops.rs +0 -9
- package/crates/team-agent/src/lifecycle/tests/fixtures/pi_native_mcp_host.mjs +71 -0
- package/crates/team-agent/src/lifecycle/tests/lane_ops.rs +0 -66
- package/crates/team-agent/src/lifecycle/tests/launch_spawn.rs +0 -392
- package/crates/team-agent/src/lifecycle/tests/lifecycle_lock.rs +0 -5
- package/crates/team-agent/src/lifecycle/tests/phase_golden.rs +2 -361
- package/crates/team-agent/src/lifecycle/tests/pi_dual_entry_red.rs +1 -16
- package/crates/team-agent/src/lifecycle/tests/pi_executable_mcp_red.rs +20 -112
- package/crates/team-agent/src/lifecycle/tests/pi_fork_session_inheritance_red.rs +1 -12
- package/crates/team-agent/src/lifecycle/tests/pi_native_mcp_capability_red.rs +546 -0
- package/crates/team-agent/src/lifecycle/tests.rs +1 -0
- package/crates/team-agent/src/lifecycle/worker_command_context.rs +11 -54
- package/crates/team-agent/src/messaging/tests/wave2.rs +2 -302
- package/crates/team-agent/src/model/name_similarity.rs +52 -67
- package/crates/team-agent/src/model/task_graph.rs +37 -124
- package/crates/team-agent/src/model/yaml/tests.rs +46 -165
- package/crates/team-agent/src/provider/model_catalog.rs +166 -3
- package/crates/team-agent/src/provider/testdata/cursor-list-models-native.stdout +250 -0
- package/crates/team-agent/src/provider/testdata/grok-models-authenticated.stdout +9 -0
- package/crates/team-agent/src/provider/testdata/grok-models-unauthenticated.stdout +7 -0
- package/crates/team-agent/src/provider/tests/adapter.rs +0 -20
- package/crates/team-agent/src/provider/tests/classify.rs +106 -198
- package/crates/team-agent/src/tmux_backend/tests.rs +178 -501
- package/crates/team-agent/src/transport/tests/wire.rs +0 -55
- package/package.json +4 -4
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
Available models
|
|
2
|
+
|
|
3
|
+
auto - Auto (default)
|
|
4
|
+
gpt-5.3-codex-low - Codex 5.3 Low
|
|
5
|
+
gpt-5.3-codex-low-fast - Codex 5.3 Low Fast
|
|
6
|
+
gpt-5.3-codex - Codex 5.3
|
|
7
|
+
gpt-5.3-codex-fast - Codex 5.3 Fast
|
|
8
|
+
gpt-5.3-codex-high - Codex 5.3 High
|
|
9
|
+
gpt-5.3-codex-high-fast - Codex 5.3 High Fast
|
|
10
|
+
gpt-5.3-codex-xhigh - Codex 5.3 Extra High
|
|
11
|
+
gpt-5.3-codex-xhigh-fast - Codex 5.3 Extra High Fast
|
|
12
|
+
gpt-5.2 - GPT-5.2
|
|
13
|
+
composer-2.5 - Composer 2.5
|
|
14
|
+
claude-opus-5-thinking-high - Claude Opus 5 1M Thinking
|
|
15
|
+
claude-opus-5-thinking-high-fast - Claude Opus 5 1M Thinking Fast
|
|
16
|
+
gpt-5.6-sol-high - GPT-5.6 Sol 1M High
|
|
17
|
+
gpt-5.6-sol-high-fast - GPT-5.6 Sol 1M High Fast
|
|
18
|
+
gpt-5.6-sol-xhigh - GPT-5.6 Sol 1M Extra High
|
|
19
|
+
gpt-5.6-sol-xhigh-fast - GPT-5.6 Sol 1M Extra High Fast
|
|
20
|
+
claude-fable-5-thinking-high - Claude Fable 5 1M Thinking (NO ZDR)
|
|
21
|
+
claude-fable-5-thinking-xhigh - Claude Fable 5 1M Extra High Thinking (NO ZDR)
|
|
22
|
+
cursor-grok-4.5-high - Grok 4.5
|
|
23
|
+
cursor-grok-4.5-high-fast - Grok 4.5 Fast
|
|
24
|
+
gemini-3.7-flash-high - Gemini 3.7 Flash
|
|
25
|
+
claude-sonnet-5-thinking-high - Claude Sonnet 5 1M Thinking
|
|
26
|
+
claude-sonnet-5-thinking-xhigh - Claude Sonnet 5 1M Extra High Thinking
|
|
27
|
+
gpt-5.6-luna-high - GPT-5.6 Luna 1M High
|
|
28
|
+
grok-4.7-low - Grok 4.7 Low
|
|
29
|
+
grok-4.7-low-fast - Grok 4.7 Low Fast
|
|
30
|
+
grok-4.7-medium - Grok 4.7 Medium
|
|
31
|
+
grok-4.7-medium-fast - Grok 4.7 Medium Fast
|
|
32
|
+
grok-4.7-high - Grok 4.7 High
|
|
33
|
+
grok-4.7-high-fast - Grok 4.7 High Fast
|
|
34
|
+
grok-4.7-xhigh - Grok 4.7 Extra High
|
|
35
|
+
grok-4.7-xhigh-fast - Grok 4.7 Extra High Fast
|
|
36
|
+
cursor-grok-4.6-low - Grok 4.6 Low
|
|
37
|
+
cursor-grok-4.6-low-fast - Grok 4.6 Low Fast
|
|
38
|
+
cursor-grok-4.6-medium - Grok 4.6 Medium
|
|
39
|
+
cursor-grok-4.6-medium-fast - Grok 4.6 Medium Fast
|
|
40
|
+
cursor-grok-4.6-high - Grok 4.6
|
|
41
|
+
cursor-grok-4.6-high-fast - Grok 4.6 Fast
|
|
42
|
+
cursor-grok-4.6-xhigh - Grok 4.6 Extra High
|
|
43
|
+
cursor-grok-4.6-xhigh-fast - Grok 4.6 Extra High Fast
|
|
44
|
+
composer-2.5-fast - Composer 2.5 Fast
|
|
45
|
+
claude-opus-5-5-low - Claude Opus 5.5 1M Low
|
|
46
|
+
claude-opus-5-5-low-fast - Claude Opus 5.5 1M Low Fast
|
|
47
|
+
claude-opus-5-5-medium - Claude Opus 5.5 1M
|
|
48
|
+
claude-opus-5-5-medium-fast - Claude Opus 5.5 1M Fast
|
|
49
|
+
claude-opus-5-5-high - Claude Opus 5.5 1M High
|
|
50
|
+
claude-opus-5-5-high-fast - Claude Opus 5.5 1M High Fast
|
|
51
|
+
claude-opus-5-5-xhigh - Claude Opus 5.5 1M Extra High
|
|
52
|
+
claude-opus-5-5-xhigh-fast - Claude Opus 5.5 1M Extra High Fast
|
|
53
|
+
claude-opus-5-5-max - Claude Opus 5.5 1M Max
|
|
54
|
+
claude-opus-5-5-max-fast - Claude Opus 5.5 1M Max Fast
|
|
55
|
+
claude-opus-5-low - Claude Opus 5 1M Low
|
|
56
|
+
claude-opus-5-low-fast - Claude Opus 5 1M Low Fast
|
|
57
|
+
claude-opus-5-medium - Claude Opus 5 1M Medium
|
|
58
|
+
claude-opus-5-medium-fast - Claude Opus 5 1M Medium Fast
|
|
59
|
+
claude-opus-5-high - Claude Opus 5 1M
|
|
60
|
+
claude-opus-5-high-fast - Claude Opus 5 1M Fast
|
|
61
|
+
claude-opus-5-thinking-low - Claude Opus 5 1M Low Thinking
|
|
62
|
+
claude-opus-5-thinking-low-fast - Claude Opus 5 1M Low Thinking Fast
|
|
63
|
+
claude-opus-5-thinking-medium - Claude Opus 5 1M Medium Thinking
|
|
64
|
+
claude-opus-5-thinking-medium-fast - Claude Opus 5 1M Medium Thinking Fast
|
|
65
|
+
claude-opus-5-thinking-xhigh - Claude Opus 5 1M Extra High Thinking
|
|
66
|
+
claude-opus-5-thinking-xhigh-fast - Claude Opus 5 1M Extra High Thinking Fast
|
|
67
|
+
claude-opus-5-thinking-max - Claude Opus 5 1M Max Thinking
|
|
68
|
+
claude-opus-5-thinking-max-fast - Claude Opus 5 1M Max Thinking Fast
|
|
69
|
+
claude-opus-4-8-low - Claude Opus 4.8 1M Low
|
|
70
|
+
claude-opus-4-8-low-fast - Claude Opus 4.8 1M Low Fast
|
|
71
|
+
claude-opus-4-8-medium - Claude Opus 4.8 1M Medium
|
|
72
|
+
claude-opus-4-8-medium-fast - Claude Opus 4.8 1M Medium Fast
|
|
73
|
+
claude-opus-4-8-high - Claude Opus 4.8 1M
|
|
74
|
+
claude-opus-4-8-high-fast - Claude Opus 4.8 1M Fast
|
|
75
|
+
claude-opus-4-8-xhigh - Claude Opus 4.8 1M Extra High
|
|
76
|
+
claude-opus-4-8-xhigh-fast - Claude Opus 4.8 1M Extra High Fast
|
|
77
|
+
claude-opus-4-8-max - Claude Opus 4.8 1M Max
|
|
78
|
+
claude-opus-4-8-max-fast - Claude Opus 4.8 1M Max Fast
|
|
79
|
+
claude-opus-4-8-thinking-low - Claude Opus 4.8 1M Low Thinking
|
|
80
|
+
claude-opus-4-8-thinking-low-fast - Claude Opus 4.8 1M Low Thinking Fast
|
|
81
|
+
claude-opus-4-8-thinking-medium - Claude Opus 4.8 1M Medium Thinking
|
|
82
|
+
claude-opus-4-8-thinking-medium-fast - Claude Opus 4.8 1M Medium Thinking Fast
|
|
83
|
+
claude-opus-4-8-thinking-high - Claude Opus 4.8 1M Thinking
|
|
84
|
+
claude-opus-4-8-thinking-high-fast - Claude Opus 4.8 1M Thinking Fast
|
|
85
|
+
claude-opus-4-8-thinking-xhigh - Claude Opus 4.8 1M Extra High Thinking
|
|
86
|
+
claude-opus-4-8-thinking-xhigh-fast - Claude Opus 4.8 1M Extra High Thinking Fast
|
|
87
|
+
claude-opus-4-8-thinking-max - Claude Opus 4.8 1M Max Thinking
|
|
88
|
+
claude-opus-4-8-thinking-max-fast - Claude Opus 4.8 1M Max Thinking Fast
|
|
89
|
+
gpt-5.6-sol-none - GPT-5.6 Sol 1M None
|
|
90
|
+
gpt-5.6-sol-none-fast - GPT-5.6 Sol 1M None Fast
|
|
91
|
+
gpt-5.6-sol-low - GPT-5.6 Sol 1M Low
|
|
92
|
+
gpt-5.6-sol-low-fast - GPT-5.6 Sol 1M Low Fast
|
|
93
|
+
gpt-5.6-sol-medium - GPT-5.6 Sol 1M
|
|
94
|
+
gpt-5.6-sol-medium-fast - GPT-5.6 Sol 1M Fast
|
|
95
|
+
gpt-5.6-sol-max - GPT-5.6 Sol 1M Max
|
|
96
|
+
gpt-5.6-sol-max-fast - GPT-5.6 Sol 1M Max Fast
|
|
97
|
+
gpt-5.5-none - GPT-5.5 1M None
|
|
98
|
+
gpt-5.5-none-fast - GPT-5.5 None Fast
|
|
99
|
+
gpt-5.5-low - GPT-5.5 1M Low
|
|
100
|
+
gpt-5.5-low-fast - GPT-5.5 Low Fast
|
|
101
|
+
gpt-5.5-medium - GPT-5.5 1M
|
|
102
|
+
gpt-5.5-medium-fast - GPT-5.5 Fast
|
|
103
|
+
gpt-5.5-high - GPT-5.5 1M High
|
|
104
|
+
gpt-5.5-high-fast - GPT-5.5 High Fast
|
|
105
|
+
gpt-5.5-extra-high - GPT-5.5 1M Extra High
|
|
106
|
+
gpt-5.5-extra-high-fast - GPT-5.5 Extra High Fast
|
|
107
|
+
claude-fable-5-1-low - Claude Fable 5.1 1M Low (NO ZDR)
|
|
108
|
+
claude-fable-5-1-medium - Claude Fable 5.1 1M Medium (NO ZDR)
|
|
109
|
+
claude-fable-5-1-high - Claude Fable 5.1 1M (NO ZDR)
|
|
110
|
+
claude-fable-5-1-xhigh - Claude Fable 5.1 1M Extra High (NO ZDR)
|
|
111
|
+
claude-fable-5-1-max - Claude Fable 5.1 1M Max (NO ZDR)
|
|
112
|
+
claude-fable-5-1-thinking-low - Claude Fable 5.1 1M Low Thinking (NO ZDR)
|
|
113
|
+
claude-fable-5-1-thinking-medium - Claude Fable 5.1 1M Medium Thinking (NO ZDR)
|
|
114
|
+
claude-fable-5-1-thinking-high - Claude Fable 5.1 1M Thinking (NO ZDR)
|
|
115
|
+
claude-fable-5-1-thinking-xhigh - Claude Fable 5.1 1M Extra High Thinking (NO ZDR)
|
|
116
|
+
claude-fable-5-1-thinking-max - Claude Fable 5.1 1M Max Thinking (NO ZDR)
|
|
117
|
+
claude-fable-5-low - Claude Fable 5 1M Low (NO ZDR)
|
|
118
|
+
claude-fable-5-medium - Claude Fable 5 1M Medium (NO ZDR)
|
|
119
|
+
claude-fable-5-high - Claude Fable 5 1M (NO ZDR)
|
|
120
|
+
claude-fable-5-xhigh - Claude Fable 5 1M Extra High (NO ZDR)
|
|
121
|
+
claude-fable-5-max - Claude Fable 5 1M Max (NO ZDR)
|
|
122
|
+
claude-fable-5-thinking-low - Claude Fable 5 1M Low Thinking (NO ZDR)
|
|
123
|
+
claude-fable-5-thinking-medium - Claude Fable 5 1M Medium Thinking (NO ZDR)
|
|
124
|
+
claude-fable-5-thinking-max - Claude Fable 5 1M Max Thinking (NO ZDR)
|
|
125
|
+
cursor-grok-4.5-low - Grok 4.5 Low
|
|
126
|
+
cursor-grok-4.5-low-fast - Grok 4.5 Low Fast
|
|
127
|
+
cursor-grok-4.5-medium - Grok 4.5 Medium
|
|
128
|
+
cursor-grok-4.5-medium-fast - Grok 4.5 Medium Fast
|
|
129
|
+
gemini-3.8-flash-low - Gemini 3.8 Flash Low
|
|
130
|
+
gemini-3.8-flash-medium - Gemini 3.8 Flash Medium
|
|
131
|
+
gemini-3.8-flash-high - Gemini 3.8 Flash High
|
|
132
|
+
gemini-3.7-flash-low - Gemini 3.7 Flash Low
|
|
133
|
+
gemini-3.7-flash-medium - Gemini 3.7 Flash Medium
|
|
134
|
+
muse-spark-1.3-minimal - Muse Spark 1.3 1M Minimal
|
|
135
|
+
muse-spark-1.3-low - Muse Spark 1.3 1M Low
|
|
136
|
+
muse-spark-1.3-medium - Muse Spark 1.3 1M Medium
|
|
137
|
+
muse-spark-1.3-high - Muse Spark 1.3 1M
|
|
138
|
+
muse-spark-1.3-xhigh - Muse Spark 1.3 1M Extra High
|
|
139
|
+
muse-spark-1.3-max - Muse Spark 1.3 1M Max
|
|
140
|
+
gpt-5.6-terra-none - GPT-5.6 Terra 1M None
|
|
141
|
+
gpt-5.6-terra-none-fast - GPT-5.6 Terra 1M None Fast
|
|
142
|
+
gpt-5.6-terra-low - GPT-5.6 Terra 1M Low
|
|
143
|
+
gpt-5.6-terra-low-fast - GPT-5.6 Terra 1M Low Fast
|
|
144
|
+
gpt-5.6-terra-medium - GPT-5.6 Terra 1M
|
|
145
|
+
gpt-5.6-terra-medium-fast - GPT-5.6 Terra 1M Fast
|
|
146
|
+
gpt-5.6-terra-high - GPT-5.6 Terra 1M High
|
|
147
|
+
gpt-5.6-terra-high-fast - GPT-5.6 Terra 1M High Fast
|
|
148
|
+
gpt-5.6-terra-xhigh - GPT-5.6 Terra 1M Extra High
|
|
149
|
+
gpt-5.6-terra-xhigh-fast - GPT-5.6 Terra 1M Extra High Fast
|
|
150
|
+
gpt-5.6-terra-max - GPT-5.6 Terra 1M Max
|
|
151
|
+
gpt-5.6-terra-max-fast - GPT-5.6 Terra 1M Max Fast
|
|
152
|
+
claude-sonnet-5-5-low - Claude Sonnet 5.5 Low
|
|
153
|
+
claude-sonnet-5-5-medium - Claude Sonnet 5.5 Medium
|
|
154
|
+
claude-sonnet-5-5-high - Claude Sonnet 5.5 High
|
|
155
|
+
claude-sonnet-5-5-xhigh - Claude Sonnet 5.5 Extra High
|
|
156
|
+
claude-sonnet-5-5-max - Claude Sonnet 5.5 Max
|
|
157
|
+
claude-sonnet-5-low - Claude Sonnet 5 1M Low
|
|
158
|
+
claude-sonnet-5-medium - Claude Sonnet 5 1M Medium
|
|
159
|
+
claude-sonnet-5-high - Claude Sonnet 5 1M
|
|
160
|
+
claude-sonnet-5-xhigh - Claude Sonnet 5 1M Extra High
|
|
161
|
+
claude-sonnet-5-max - Claude Sonnet 5 1M Max
|
|
162
|
+
claude-sonnet-5-thinking-low - Claude Sonnet 5 1M Low Thinking
|
|
163
|
+
claude-sonnet-5-thinking-medium - Claude Sonnet 5 1M Medium Thinking
|
|
164
|
+
claude-sonnet-5-thinking-max - Claude Sonnet 5 1M Max Thinking
|
|
165
|
+
claude-4.6-sonnet-medium - Claude Sonnet 4.6 1M
|
|
166
|
+
claude-4.6-sonnet-medium-thinking - Claude Sonnet 4.6 1M Thinking
|
|
167
|
+
claude-opus-4-7-low - Claude Opus 4.7 1M Low
|
|
168
|
+
claude-opus-4-7-low-fast - Claude Opus 4.7 1M Low Fast
|
|
169
|
+
claude-opus-4-7-medium - Claude Opus 4.7 1M Medium
|
|
170
|
+
claude-opus-4-7-medium-fast - Claude Opus 4.7 1M Medium Fast
|
|
171
|
+
claude-opus-4-7-high - Claude Opus 4.7 1M High
|
|
172
|
+
claude-opus-4-7-high-fast - Claude Opus 4.7 1M High Fast
|
|
173
|
+
claude-opus-4-7-xhigh - Claude Opus 4.7 1M
|
|
174
|
+
claude-opus-4-7-xhigh-fast - Claude Opus 4.7 1M Fast
|
|
175
|
+
claude-opus-4-7-max - Claude Opus 4.7 1M Max
|
|
176
|
+
claude-opus-4-7-max-fast - Claude Opus 4.7 1M Max Fast
|
|
177
|
+
claude-opus-4-7-thinking-low - Claude Opus 4.7 1M Low Thinking
|
|
178
|
+
claude-opus-4-7-thinking-low-fast - Claude Opus 4.7 1M Low Thinking Fast
|
|
179
|
+
claude-opus-4-7-thinking-medium - Claude Opus 4.7 1M Medium Thinking
|
|
180
|
+
claude-opus-4-7-thinking-medium-fast - Claude Opus 4.7 1M Medium Thinking Fast
|
|
181
|
+
claude-opus-4-7-thinking-high - Claude Opus 4.7 1M High Thinking
|
|
182
|
+
claude-opus-4-7-thinking-high-fast - Claude Opus 4.7 1M High Thinking Fast
|
|
183
|
+
claude-opus-4-7-thinking-xhigh - Claude Opus 4.7 1M Thinking
|
|
184
|
+
claude-opus-4-7-thinking-xhigh-fast - Claude Opus 4.7 1M Thinking Fast
|
|
185
|
+
claude-opus-4-7-thinking-max - Claude Opus 4.7 1M Max Thinking
|
|
186
|
+
claude-opus-4-7-thinking-max-fast - Claude Opus 4.7 1M Max Thinking Fast
|
|
187
|
+
gpt-5.4-low - GPT-5.4 1M Low
|
|
188
|
+
gpt-5.4-medium - GPT-5.4 1M
|
|
189
|
+
gpt-5.4-medium-fast - GPT-5.4 Fast
|
|
190
|
+
gpt-5.4-high - GPT-5.4 1M High
|
|
191
|
+
gpt-5.4-high-fast - GPT-5.4 High Fast
|
|
192
|
+
gpt-5.4-xhigh - GPT-5.4 1M Extra High
|
|
193
|
+
gpt-5.4-xhigh-fast - GPT-5.4 Extra High Fast
|
|
194
|
+
claude-4.6-opus-high - Claude Opus 4.6 1M
|
|
195
|
+
claude-4.6-opus-max - Claude Opus 4.6 1M Max
|
|
196
|
+
claude-4.6-opus-high-thinking - Claude Opus 4.6 1M Thinking
|
|
197
|
+
claude-4.6-opus-max-thinking - Claude Opus 4.6 1M Max Thinking
|
|
198
|
+
claude-4.5-opus-high - Claude Opus 4.5
|
|
199
|
+
claude-4.5-opus-high-thinking - Claude Opus 4.5 Thinking
|
|
200
|
+
gpt-5.2-low - GPT-5.2 Low
|
|
201
|
+
gpt-5.2-low-fast - GPT-5.2 Low Fast
|
|
202
|
+
gpt-5.2-fast - GPT-5.2 Fast
|
|
203
|
+
gpt-5.2-high - GPT-5.2 High
|
|
204
|
+
gpt-5.2-high-fast - GPT-5.2 High Fast
|
|
205
|
+
gpt-5.2-xhigh - GPT-5.2 Extra High
|
|
206
|
+
gpt-5.2-xhigh-fast - GPT-5.2 Extra High Fast
|
|
207
|
+
gpt-5.6-luna-none - GPT-5.6 Luna 1M None
|
|
208
|
+
gpt-5.6-luna-none-fast - GPT-5.6 Luna 1M None Fast
|
|
209
|
+
gpt-5.6-luna-low - GPT-5.6 Luna 1M Low (current)
|
|
210
|
+
gpt-5.6-luna-low-fast - GPT-5.6 Luna 1M Low Fast
|
|
211
|
+
gpt-5.6-luna-medium - GPT-5.6 Luna 1M
|
|
212
|
+
gpt-5.6-luna-medium-fast - GPT-5.6 Luna 1M Fast
|
|
213
|
+
gpt-5.6-luna-high-fast - GPT-5.6 Luna 1M High Fast
|
|
214
|
+
gpt-5.6-luna-xhigh - GPT-5.6 Luna 1M Extra High
|
|
215
|
+
gpt-5.6-luna-xhigh-fast - GPT-5.6 Luna 1M Extra High Fast
|
|
216
|
+
gpt-5.6-luna-max - GPT-5.6 Luna 1M Max
|
|
217
|
+
gpt-5.6-luna-max-fast - GPT-5.6 Luna 1M Max Fast
|
|
218
|
+
gemini-3.6-flash-minimal - Gemini 3.6 Flash Minimal
|
|
219
|
+
gemini-3.6-flash-low - Gemini 3.6 Flash Low
|
|
220
|
+
gemini-3.6-flash-medium - Gemini 3.6 Flash Medium
|
|
221
|
+
gemini-3.6-flash-high - Gemini 3.6 Flash
|
|
222
|
+
gemini-3.1-pro - Gemini 3.1 Pro
|
|
223
|
+
gpt-5.4-mini-none - GPT-5.4 Mini None
|
|
224
|
+
gpt-5.4-mini-low - GPT-5.4 Mini Low
|
|
225
|
+
gpt-5.4-mini-medium - GPT-5.4 Mini
|
|
226
|
+
gpt-5.4-mini-high - GPT-5.4 Mini High
|
|
227
|
+
gpt-5.4-mini-xhigh - GPT-5.4 Mini Extra High
|
|
228
|
+
gpt-5.4-nano-none - GPT-5.4 Nano None
|
|
229
|
+
gpt-5.4-nano-low - GPT-5.4 Nano Low
|
|
230
|
+
gpt-5.4-nano-medium - GPT-5.4 Nano
|
|
231
|
+
gpt-5.4-nano-high - GPT-5.4 Nano High
|
|
232
|
+
gpt-5.4-nano-xhigh - GPT-5.4 Nano Extra High
|
|
233
|
+
claude-4.5-sonnet - Claude Sonnet 4.5
|
|
234
|
+
claude-4.5-sonnet-thinking - Claude Sonnet 4.5 Thinking
|
|
235
|
+
gpt-5.1-low - GPT-5.1 Low
|
|
236
|
+
gpt-5.1 - GPT-5.1
|
|
237
|
+
gpt-5.1-high - GPT-5.1 High
|
|
238
|
+
gemini-3-flash - Gemini 3 Flash
|
|
239
|
+
gemini-3.5-flash - Gemini 3.5 Flash
|
|
240
|
+
claude-4-sonnet - Claude Sonnet 4
|
|
241
|
+
claude-4-sonnet-thinking - Claude Sonnet 4 Thinking
|
|
242
|
+
gpt-5-mini - GPT-5 Mini
|
|
243
|
+
kimi-k3-low - Kimi K3 Low
|
|
244
|
+
kimi-k3-high - Kimi K3 High
|
|
245
|
+
kimi-k3-max - Kimi K3
|
|
246
|
+
kimi-k2.7-code - Kimi K2.7 Code
|
|
247
|
+
glm-5.2-high - GLM 5.2
|
|
248
|
+
glm-5.2-max - GLM 5.2 Max
|
|
249
|
+
|
|
250
|
+
Tip: use --model <id> (or /model <id> in interactive mode) to switch. Parameterized models also accept quoted overrides, e.g. --model 'claude-opus-4-8[context=1m,effort=high,fast=false]'.
|
|
@@ -403,26 +403,6 @@ fn test_cursor_agent_accepts_mcp_config_without_putting_it_on_argv() {
|
|
|
403
403
|
);
|
|
404
404
|
}
|
|
405
405
|
|
|
406
|
-
#[test]
|
|
407
|
-
fn test_cursor_agent_refuses_mcp_config_loudly() {
|
|
408
|
-
// 已废除的行为:旧实现收到 mcp_config 就返回 CapabilityUnsupported
|
|
409
|
-
// (「MCP is not implemented」),此断言证明它确实没了。
|
|
410
|
-
let adapter = get_adapter(Provider::CursorAgent);
|
|
411
|
-
let cfg = McpConfig {
|
|
412
|
-
raw: serde_json::json!({
|
|
413
|
-
"team_orchestrator": {
|
|
414
|
-
"command": "/bin/team-agent",
|
|
415
|
-
"args": ["mcp-server"]
|
|
416
|
-
}
|
|
417
|
-
}),
|
|
418
|
-
};
|
|
419
|
-
let result = adapter.build_command(AuthMode::Subscription, Some(&cfg), None, None);
|
|
420
|
-
assert!(
|
|
421
|
-
!matches!(result, Err(ProviderError::CapabilityUnsupported(_))),
|
|
422
|
-
"feeding mcp_config must not return CapabilityUnsupported; got {result:?}"
|
|
423
|
-
);
|
|
424
|
-
}
|
|
425
|
-
|
|
426
406
|
#[test]
|
|
427
407
|
fn test_grok_build_command_plan_binds_expected_session_id_to_argv() {
|
|
428
408
|
let adapter = get_adapter(Provider::Grok);
|
|
@@ -6,53 +6,113 @@ fn claude_open_turn() -> String {
|
|
|
6
6
|
}
|
|
7
7
|
|
|
8
8
|
#[test]
|
|
9
|
-
fn
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
"unreadable/empty input must never be idle (C5)"
|
|
9
|
+
fn classify_state_table() {
|
|
10
|
+
use ClassifySource::{ProcessGuard, SessionFile};
|
|
11
|
+
use ProcessLiveness::{Alive, Unverifiable};
|
|
12
|
+
use Provider::{Claude, ClaudeCode, Codex};
|
|
13
|
+
use TurnState::{Abnormal, BlockedOnHuman, Idle, IdleInterrupted, Unknown, Working};
|
|
14
|
+
|
|
15
|
+
type Input<'a> = (Provider, &'a str, ProcessLiveness, f64);
|
|
16
|
+
// State, reason, turn ID, source, exact annotations, idle-for-takeover.
|
|
17
|
+
// None skips an originally absent assertion; Some(None) asserts no turn ID.
|
|
18
|
+
type Expected<'a> = (
|
|
19
|
+
TurnState, &'a str, Option<Option<&'a str>>, Option<ClassifySource>,
|
|
20
|
+
Option<&'a [&'a str]>, Option<bool>,
|
|
22
21
|
);
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
22
|
+
let open = claude_open_turn();
|
|
23
|
+
let two = format!(
|
|
24
|
+
"{}\n{}",
|
|
25
|
+
r#"{"type":"assistant","requestId":"a","message":{"stop_reason":"tool_use"}}"#,
|
|
26
|
+
r#"{"type":"assistant","requestId":"b","message":{"stop_reason":"end_turn"}}"#,
|
|
27
|
+
);
|
|
28
|
+
let c14 = format!(
|
|
29
|
+
"{}\n{}",
|
|
30
|
+
r#"{"type":"assistant","requestId":"a","message":{"stop_reason":"end_turn"}}"#,
|
|
31
|
+
r#"{"type":"assistant","requestId":"b","message":{"stop_reason":"tool_use"}}"#,
|
|
32
|
+
);
|
|
33
|
+
let cases: &[(&str, Input<'_>, Expected<'_>)] = &[
|
|
34
|
+
// Unknown is NEVER idle (bug-071/077/085, C5).
|
|
35
|
+
("empty",
|
|
36
|
+
(ClaudeCode, "", Unverifiable, 0.0),
|
|
37
|
+
(Unknown, "unreadable_or_empty", Some(None), Some(SessionFile), None, Some(false))),
|
|
38
|
+
("whitespace",
|
|
39
|
+
(Claude, " \n \t \n", Unverifiable, 0.0),
|
|
40
|
+
(Unknown, "unreadable_or_empty", None, None, None, Some(false))),
|
|
41
|
+
// !had_records wins over parse diagnostics (common.py:72-75).
|
|
42
|
+
("garbage_jsonl",
|
|
43
|
+
(Claude, "not json\n{broken", Unverifiable, 0.0),
|
|
44
|
+
(Unknown, "unreadable_or_empty", None, None, None, Some(false))),
|
|
45
|
+
// Valid record without lifecycle facts: NOT unrecognized_format.
|
|
46
|
+
("unrecognized_record",
|
|
47
|
+
(Claude, r#"{"foo":"bar"}"#, Unverifiable, 0.0),
|
|
48
|
+
(Unknown, "no_turn_lifecycle_fact", None, None, None, Some(false))),
|
|
49
|
+
// C4: missing process identity is NEVER optimistically working.
|
|
50
|
+
("open_unverifiable_identity",
|
|
51
|
+
(Claude, &open, Unverifiable, 0.0),
|
|
52
|
+
(Unknown, "process_identity_unverified", Some(Some("r1")), Some(ProcessGuard), None, Some(false))),
|
|
53
|
+
("open_alive",
|
|
54
|
+
(Claude, &open, Alive, 0.0),
|
|
55
|
+
(Working, "open_turn", Some(Some("r1")), Some(SessionFile), None, None)),
|
|
56
|
+
("open_unverifiable_process",
|
|
57
|
+
(Claude, &open, Unverifiable, 0.0),
|
|
58
|
+
(Unknown, "process_identity_unverified", None, None, None, Some(false))),
|
|
59
|
+
("last_fact_wins",
|
|
60
|
+
(Claude, &two, Unverifiable, 0.0),
|
|
61
|
+
(Idle, "end_turn", Some(Some("b")), None, None, None)),
|
|
62
|
+
// C14: silence is discarded; only a dead process can demote an open turn.
|
|
63
|
+
("open_beats_silence",
|
|
64
|
+
(Claude, &c14, Alive, 9999.0),
|
|
65
|
+
(Working, "open_turn", Some(Some("b")), None, None, None)),
|
|
66
|
+
// C12: idle_interrupted IS idle for take-over, with exact annotations.
|
|
67
|
+
("claude_interrupted",
|
|
68
|
+
(Claude, r#"{"type":"user","uuid":"u1","message":{"content":[{"type":"text","text":"[Request interrupted by user]"}]}}"#, Unverifiable, 0.0),
|
|
69
|
+
(IdleInterrupted, "user_interrupt", Some(Some("u1")), None, Some(&["interrupted"]), Some(true))),
|
|
70
|
+
("claude_stop_sequence",
|
|
71
|
+
(Claude, r#"{"type":"assistant","requestId":"r1","message":{"stop_reason":"stop_sequence"}}"#, Unverifiable, 0.0),
|
|
72
|
+
(Idle, "stop_sequence", None, None, None, None)),
|
|
73
|
+
("codex_task_complete",
|
|
74
|
+
(Codex, r#"{"type":"event_msg","payload":{"type":"task_complete","turn_id":"ct1"}}"#, Unverifiable, 0.0),
|
|
75
|
+
(Idle, "task_complete", Some(Some("ct1")), None, None, None)),
|
|
76
|
+
("codex_abort_interrupted",
|
|
77
|
+
(Codex, r#"{"type":"event_msg","payload":{"type":"turn_aborted","turn_id":"ct2","reason":"interrupted"}}"#, Unverifiable, 0.0),
|
|
78
|
+
(IdleInterrupted, "interrupted", None, None, None, None)),
|
|
79
|
+
// Raw abort reason must pass through, including non-interrupted errors.
|
|
80
|
+
("codex_abort_error",
|
|
81
|
+
(Codex, r#"{"type":"event_msg","payload":{"type":"turn_aborted","turn_id":"ct3","reason":"error"}}"#, Unverifiable, 0.0),
|
|
82
|
+
(IdleInterrupted, "error", Some(Some("ct3")), None, None, None)),
|
|
83
|
+
("codex_turn_failed",
|
|
84
|
+
(Codex, r#"{"jsonrpc":"2.0","method":"turn/completed","params":{"turn":{"id":"ct4","status":"failed"}}}"#, Unverifiable, 0.0),
|
|
85
|
+
(Abnormal, "turn_failed", Some(Some("ct4")), None, Some(&["turn_failed"]), Some(false))),
|
|
86
|
+
// blocked_on_human is NOT idle for take-over.
|
|
87
|
+
("codex_approval",
|
|
88
|
+
(Codex, r#"{"jsonrpc":"2.0","method":"session/requestApproval","params":{"turnId":"ct5"}}"#, Unverifiable, 0.0),
|
|
89
|
+
(BlockedOnHuman, "approval_required", Some(Some("ct5")), None, Some(&["awaiting_approval"]), Some(false))),
|
|
90
|
+
];
|
|
91
|
+
for &(id, (provider, text, liveness, silence), expected) in cases {
|
|
92
|
+
let c = classify(provider, text, liveness, silence)
|
|
93
|
+
.unwrap_or_else(|err| panic!("{id}: classify failed: {err:?}"));
|
|
94
|
+
let (state, reason, turn_id, source, annotations, idle) = expected;
|
|
95
|
+
let note = match id {
|
|
96
|
+
"empty" => "unreadable/empty input must never be idle (C5)",
|
|
97
|
+
"codex_abort_error" => "raw abort reason must pass through",
|
|
98
|
+
_ => "",
|
|
99
|
+
};
|
|
100
|
+
assert_eq!(c.state, state, "{id}: state");
|
|
101
|
+
assert_eq!(c.reason, reason, "{id}: reason; {note}");
|
|
102
|
+
if let Some(turn_id) = turn_id {
|
|
103
|
+
assert_eq!(c.turn_id.as_ref().map(TurnId::as_str), turn_id, "{id}: turn ID");
|
|
104
|
+
}
|
|
105
|
+
if let Some(source) = source {
|
|
106
|
+
assert_eq!(c.source, source, "{id}: source");
|
|
107
|
+
}
|
|
108
|
+
if let Some(annotations) = annotations {
|
|
109
|
+
let actual: Vec<_> = c.annotations.iter().map(String::as_str).collect();
|
|
110
|
+
assert_eq!(actual.as_slice(), annotations, "{id}: exact annotations");
|
|
111
|
+
}
|
|
112
|
+
if let Some(idle) = idle {
|
|
113
|
+
assert_eq!(c.state.is_idle_for_takeover(), idle, "{id}: idle-for-takeover; {note}");
|
|
114
|
+
}
|
|
115
|
+
}
|
|
56
116
|
}
|
|
57
117
|
|
|
58
118
|
#[test]
|
|
@@ -69,31 +129,6 @@ fn classify_claude_code_alias_normalizes_to_claude_reader() {
|
|
|
69
129
|
assert_eq!(alias, canon, "claude_code must normalize to the claude reader");
|
|
70
130
|
}
|
|
71
131
|
|
|
72
|
-
#[test]
|
|
73
|
-
fn classify_open_turn_with_no_process_is_unknown_not_working() {
|
|
74
|
-
// probe open_turn_process_none: open turn + Unverifiable (None process) →
|
|
75
|
-
// unknown / process_identity_unverified / source=process_guard, turn_id=r1.
|
|
76
|
-
// C4: missing identity is NEVER optimistically working.
|
|
77
|
-
let c = classify(Provider::Claude, &claude_open_turn(), ProcessLiveness::Unverifiable, 0.0)
|
|
78
|
-
.expect("classify ok");
|
|
79
|
-
assert_eq!(c.state, TurnState::Unknown);
|
|
80
|
-
assert_eq!(c.reason, "process_identity_unverified");
|
|
81
|
-
assert_eq!(c.source, ClassifySource::ProcessGuard);
|
|
82
|
-
assert_eq!(c.turn_id, Some(TurnId::new("r1")));
|
|
83
|
-
assert!(!c.state.is_idle_for_takeover());
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
#[test]
|
|
87
|
-
fn classify_open_turn_alive_is_working() {
|
|
88
|
-
// probe open_turn_alive: open turn + Alive → working / open_turn / source=session_file.
|
|
89
|
-
let c = classify(Provider::Claude, &claude_open_turn(), ProcessLiveness::Alive, 0.0)
|
|
90
|
-
.expect("classify ok");
|
|
91
|
-
assert_eq!(c.state, TurnState::Working);
|
|
92
|
-
assert_eq!(c.reason, "open_turn");
|
|
93
|
-
assert_eq!(c.source, ClassifySource::SessionFile);
|
|
94
|
-
assert_eq!(c.turn_id, Some(TurnId::new("r1")));
|
|
95
|
-
}
|
|
96
|
-
|
|
97
132
|
#[test]
|
|
98
133
|
fn classify_open_turn_dead_is_abnormal_crashed_mid_turn() {
|
|
99
134
|
// probe open_turn_dead: open turn + Dead → abnormal / crashed_mid_turn /
|
|
@@ -106,133 +141,6 @@ fn classify_open_turn_dead_is_abnormal_crashed_mid_turn() {
|
|
|
106
141
|
assert!(c.annotations.contains(&"crashed_mid_turn".to_string()));
|
|
107
142
|
}
|
|
108
143
|
|
|
109
|
-
#[test]
|
|
110
|
-
fn classify_open_turn_unverifiable_process_is_unknown() {
|
|
111
|
-
// probe open_turn_unverifiable: open turn + Unverifiable →
|
|
112
|
-
// unknown / process_identity_unverified (NOT working). NEVER idle.
|
|
113
|
-
let c = classify(Provider::Claude, &claude_open_turn(), ProcessLiveness::Unverifiable, 0.0)
|
|
114
|
-
.expect("classify ok");
|
|
115
|
-
assert_eq!(c.state, TurnState::Unknown);
|
|
116
|
-
assert_eq!(c.reason, "process_identity_unverified");
|
|
117
|
-
assert!(!c.state.is_idle_for_takeover());
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
#[test]
|
|
121
|
-
fn classify_last_lifecycle_fact_wins() {
|
|
122
|
-
// probe last_fact_wins_complete (tool_use 'a' then end_turn 'b') →
|
|
123
|
-
// idle / end_turn, turn_id = the LAST lifecycle fact's id ("b").
|
|
124
|
-
let two = format!(
|
|
125
|
-
"{}\n{}",
|
|
126
|
-
r#"{"type":"assistant","requestId":"a","message":{"stop_reason":"tool_use"}}"#,
|
|
127
|
-
r#"{"type":"assistant","requestId":"b","message":{"stop_reason":"end_turn"}}"#,
|
|
128
|
-
);
|
|
129
|
-
let c = classify(Provider::Claude, &two, ProcessLiveness::Unverifiable, 0.0)
|
|
130
|
-
.expect("classify ok");
|
|
131
|
-
assert_eq!(c.state, TurnState::Idle);
|
|
132
|
-
assert_eq!(c.reason, "end_turn");
|
|
133
|
-
assert_eq!(c.turn_id, Some(TurnId::new("b")));
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
#[test]
|
|
137
|
-
fn classify_c14_open_turn_beats_silence() {
|
|
138
|
-
// probe c14_open_after_complete_alive (end_turn 'a' then tool_use 'b', alive,
|
|
139
|
-
// file_silence=9999) → working / open_turn, turn_id="b". Silence is DISCARDED:
|
|
140
|
-
// only a dead process guard can demote an open turn (common.py:93-103, C14).
|
|
141
|
-
let c14 = format!(
|
|
142
|
-
"{}\n{}",
|
|
143
|
-
r#"{"type":"assistant","requestId":"a","message":{"stop_reason":"end_turn"}}"#,
|
|
144
|
-
r#"{"type":"assistant","requestId":"b","message":{"stop_reason":"tool_use"}}"#,
|
|
145
|
-
);
|
|
146
|
-
let c = classify(Provider::Claude, &c14, ProcessLiveness::Alive, 9999.0)
|
|
147
|
-
.expect("classify ok");
|
|
148
|
-
assert_eq!(c.state, TurnState::Working);
|
|
149
|
-
assert_eq!(c.reason, "open_turn");
|
|
150
|
-
assert_eq!(c.turn_id, Some(TurnId::new("b")));
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
#[test]
|
|
154
|
-
fn classify_claude_interrupted_is_idle_interrupted_annotated() {
|
|
155
|
-
// probe claude_interrupted ("[Request interrupted by user]") →
|
|
156
|
-
// idle_interrupted / user_interrupt / annotations=["interrupted"], turn_id=u1.
|
|
157
|
-
let txt = r#"{"type":"user","uuid":"u1","message":{"content":[{"type":"text","text":"[Request interrupted by user]"}]}}"#;
|
|
158
|
-
let c = classify(Provider::Claude, txt, ProcessLiveness::Unverifiable, 0.0)
|
|
159
|
-
.expect("classify ok");
|
|
160
|
-
assert_eq!(c.state, TurnState::IdleInterrupted);
|
|
161
|
-
assert_eq!(c.reason, "user_interrupt");
|
|
162
|
-
assert_eq!(c.annotations, vec!["interrupted".to_string()]);
|
|
163
|
-
assert_eq!(c.turn_id, Some(TurnId::new("u1")));
|
|
164
|
-
// C12: idle_interrupted IS idle for take-over (annotated).
|
|
165
|
-
assert!(c.state.is_idle_for_takeover());
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
#[test]
|
|
169
|
-
fn classify_claude_stop_sequence_is_idle() {
|
|
170
|
-
// probe claude_stop_sequence → idle / stop_sequence.
|
|
171
|
-
let txt = r#"{"type":"assistant","requestId":"r1","message":{"stop_reason":"stop_sequence"}}"#;
|
|
172
|
-
let c = classify(Provider::Claude, txt, ProcessLiveness::Unverifiable, 0.0)
|
|
173
|
-
.expect("classify ok");
|
|
174
|
-
assert_eq!(c.state, TurnState::Idle);
|
|
175
|
-
assert_eq!(c.reason, "stop_sequence");
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
#[test]
|
|
179
|
-
fn classify_codex_task_complete_is_idle() {
|
|
180
|
-
// probe codex_task_complete → idle / task_complete, turn_id from payload (ct1).
|
|
181
|
-
let txt = r#"{"type":"event_msg","payload":{"type":"task_complete","turn_id":"ct1"}}"#;
|
|
182
|
-
let c = classify(Provider::Codex, txt, ProcessLiveness::Unverifiable, 0.0)
|
|
183
|
-
.expect("classify ok");
|
|
184
|
-
assert_eq!(c.state, TurnState::Idle);
|
|
185
|
-
assert_eq!(c.reason, "task_complete");
|
|
186
|
-
assert_eq!(c.turn_id, Some(TurnId::new("ct1")));
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
#[test]
|
|
190
|
-
fn classify_codex_turn_aborted_interrupted_is_idle_interrupted() {
|
|
191
|
-
// probe codex_turn_aborted_interrupted → idle_interrupted / interrupted.
|
|
192
|
-
let interrupted = r#"{"type":"event_msg","payload":{"type":"turn_aborted","turn_id":"ct2","reason":"interrupted"}}"#;
|
|
193
|
-
let c = classify(Provider::Codex, interrupted, ProcessLiveness::Unverifiable, 0.0)
|
|
194
|
-
.expect("classify ok");
|
|
195
|
-
assert_eq!(c.state, TurnState::IdleInterrupted);
|
|
196
|
-
assert_eq!(c.reason, "interrupted");
|
|
197
|
-
// probe codex_turn_aborted_other (reason="error") → idle_interrupted with the
|
|
198
|
-
// RAW reason string passed through ("error"), turn_id=ct3.
|
|
199
|
-
let other = r#"{"type":"event_msg","payload":{"type":"turn_aborted","turn_id":"ct3","reason":"error"}}"#;
|
|
200
|
-
let c2 = classify(Provider::Codex, other, ProcessLiveness::Unverifiable, 0.0)
|
|
201
|
-
.expect("classify ok");
|
|
202
|
-
assert_eq!(c2.state, TurnState::IdleInterrupted);
|
|
203
|
-
assert_eq!(c2.reason, "error", "raw abort reason must pass through");
|
|
204
|
-
assert_eq!(c2.turn_id, Some(TurnId::new("ct3")));
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
#[test]
|
|
208
|
-
fn classify_codex_appserver_failed_is_abnormal() {
|
|
209
|
-
// probe codex_appserver_failed (turn.status==failed) → abnormal / turn_failed /
|
|
210
|
-
// annotations=["turn_failed"], source=session_file, turn_id=ct4.
|
|
211
|
-
let txt = r#"{"jsonrpc":"2.0","method":"turn/completed","params":{"turn":{"id":"ct4","status":"failed"}}}"#;
|
|
212
|
-
let c = classify(Provider::Codex, txt, ProcessLiveness::Unverifiable, 0.0)
|
|
213
|
-
.expect("classify ok");
|
|
214
|
-
assert_eq!(c.state, TurnState::Abnormal);
|
|
215
|
-
assert_eq!(c.reason, "turn_failed");
|
|
216
|
-
assert_eq!(c.annotations, vec!["turn_failed".to_string()]);
|
|
217
|
-
assert_eq!(c.turn_id, Some(TurnId::new("ct4")));
|
|
218
|
-
assert!(!c.state.is_idle_for_takeover());
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
#[test]
|
|
222
|
-
fn classify_codex_appserver_approval_is_blocked_on_human() {
|
|
223
|
-
// probe codex_appserver_approval (method endswith requestApproval) →
|
|
224
|
-
// blocked_on_human / approval_required / annotations=["awaiting_approval"], turn_id=ct5.
|
|
225
|
-
let txt = r#"{"jsonrpc":"2.0","method":"session/requestApproval","params":{"turnId":"ct5"}}"#;
|
|
226
|
-
let c = classify(Provider::Codex, txt, ProcessLiveness::Unverifiable, 0.0)
|
|
227
|
-
.expect("classify ok");
|
|
228
|
-
assert_eq!(c.state, TurnState::BlockedOnHuman);
|
|
229
|
-
assert_eq!(c.reason, "approval_required");
|
|
230
|
-
assert_eq!(c.annotations, vec!["awaiting_approval".to_string()]);
|
|
231
|
-
assert_eq!(c.turn_id, Some(TurnId::new("ct5")));
|
|
232
|
-
// blocked_on_human is NOT idle for take-over.
|
|
233
|
-
assert!(!c.state.is_idle_for_takeover());
|
|
234
|
-
}
|
|
235
|
-
|
|
236
144
|
// ---- (b) idle predicate / evaluate_takeover_reminder (NoPingReason cases) ----
|
|
237
145
|
//
|
|
238
146
|
// Golden via /tmp/probe_idle.py (idle_predicate.evaluate_takeover_reminder).
|