EvoScientist 0.0.1.dev4__py3-none-any.whl → 0.1.0rc2__py3-none-any.whl
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.
- EvoScientist/EvoScientist.py +25 -61
- EvoScientist/__init__.py +0 -19
- EvoScientist/backends.py +0 -26
- EvoScientist/cli.py +1365 -480
- EvoScientist/middleware.py +7 -56
- EvoScientist/skills/clip/SKILL.md +253 -0
- EvoScientist/skills/clip/references/applications.md +207 -0
- EvoScientist/skills/langgraph-docs/SKILL.md +36 -0
- EvoScientist/skills/tensorboard/SKILL.md +629 -0
- EvoScientist/skills/tensorboard/references/integrations.md +638 -0
- EvoScientist/skills/tensorboard/references/profiling.md +545 -0
- EvoScientist/skills/tensorboard/references/visualization.md +620 -0
- EvoScientist/skills/vllm/SKILL.md +364 -0
- EvoScientist/skills/vllm/references/optimization.md +226 -0
- EvoScientist/skills/vllm/references/quantization.md +284 -0
- EvoScientist/skills/vllm/references/server-deployment.md +255 -0
- EvoScientist/skills/vllm/references/troubleshooting.md +447 -0
- EvoScientist/stream/__init__.py +0 -25
- EvoScientist/stream/utils.py +16 -23
- EvoScientist/tools.py +2 -75
- {evoscientist-0.0.1.dev4.dist-info → evoscientist-0.1.0rc2.dist-info}/METADATA +8 -153
- {evoscientist-0.0.1.dev4.dist-info → evoscientist-0.1.0rc2.dist-info}/RECORD +26 -24
- evoscientist-0.1.0rc2.dist-info/entry_points.txt +2 -0
- EvoScientist/config.py +0 -274
- EvoScientist/llm/__init__.py +0 -21
- EvoScientist/llm/models.py +0 -99
- EvoScientist/memory.py +0 -715
- EvoScientist/onboard.py +0 -725
- EvoScientist/paths.py +0 -44
- EvoScientist/skills_manager.py +0 -391
- EvoScientist/stream/display.py +0 -604
- EvoScientist/stream/events.py +0 -415
- EvoScientist/stream/state.py +0 -343
- evoscientist-0.0.1.dev4.dist-info/entry_points.txt +0 -5
- {evoscientist-0.0.1.dev4.dist-info → evoscientist-0.1.0rc2.dist-info}/WHEEL +0 -0
- {evoscientist-0.0.1.dev4.dist-info → evoscientist-0.1.0rc2.dist-info}/licenses/LICENSE +0 -0
- {evoscientist-0.0.1.dev4.dist-info → evoscientist-0.1.0rc2.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,447 @@
|
|
|
1
|
+
# Troubleshooting Guide
|
|
2
|
+
|
|
3
|
+
## Contents
|
|
4
|
+
- Out of memory (OOM) errors
|
|
5
|
+
- Performance issues
|
|
6
|
+
- Model loading errors
|
|
7
|
+
- Network and connection issues
|
|
8
|
+
- Quantization problems
|
|
9
|
+
- Distributed serving issues
|
|
10
|
+
- Debugging tools and commands
|
|
11
|
+
|
|
12
|
+
## Out of memory (OOM) errors
|
|
13
|
+
|
|
14
|
+
### Symptom: `torch.cuda.OutOfMemoryError` during model loading
|
|
15
|
+
|
|
16
|
+
**Cause**: Model + KV cache exceeds available VRAM
|
|
17
|
+
|
|
18
|
+
**Solutions (try in order)**:
|
|
19
|
+
|
|
20
|
+
1. **Reduce GPU memory utilization**:
|
|
21
|
+
```bash
|
|
22
|
+
vllm serve MODEL --gpu-memory-utilization 0.7 # Try 0.7, 0.75, 0.8
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
2. **Reduce max sequence length**:
|
|
26
|
+
```bash
|
|
27
|
+
vllm serve MODEL --max-model-len 4096 # Instead of 8192
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
3. **Enable quantization**:
|
|
31
|
+
```bash
|
|
32
|
+
vllm serve MODEL --quantization awq # 4x memory reduction
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
4. **Use tensor parallelism** (multiple GPUs):
|
|
36
|
+
```bash
|
|
37
|
+
vllm serve MODEL --tensor-parallel-size 2 # Split across 2 GPUs
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
5. **Reduce max concurrent sequences**:
|
|
41
|
+
```bash
|
|
42
|
+
vllm serve MODEL --max-num-seqs 128 # Default is 256
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Symptom: OOM during inference (not model loading)
|
|
46
|
+
|
|
47
|
+
**Cause**: KV cache fills up during generation
|
|
48
|
+
|
|
49
|
+
**Solutions**:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
# Reduce KV cache allocation
|
|
53
|
+
vllm serve MODEL --gpu-memory-utilization 0.85
|
|
54
|
+
|
|
55
|
+
# Reduce batch size
|
|
56
|
+
vllm serve MODEL --max-num-seqs 64
|
|
57
|
+
|
|
58
|
+
# Reduce max tokens per request
|
|
59
|
+
# Set in client request: max_tokens=512
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Symptom: OOM with quantized model
|
|
63
|
+
|
|
64
|
+
**Cause**: Quantization overhead or incorrect configuration
|
|
65
|
+
|
|
66
|
+
**Solution**:
|
|
67
|
+
```bash
|
|
68
|
+
# Ensure quantization flag matches model
|
|
69
|
+
vllm serve TheBloke/Llama-2-70B-AWQ --quantization awq # Must specify
|
|
70
|
+
|
|
71
|
+
# Try different dtype
|
|
72
|
+
vllm serve MODEL --quantization awq --dtype float16
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Performance issues
|
|
76
|
+
|
|
77
|
+
### Symptom: Low throughput (<50 req/sec expected >100)
|
|
78
|
+
|
|
79
|
+
**Diagnostic steps**:
|
|
80
|
+
|
|
81
|
+
1. **Check GPU utilization**:
|
|
82
|
+
```bash
|
|
83
|
+
watch -n 1 nvidia-smi
|
|
84
|
+
# GPU utilization should be >80%
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
If <80%, increase concurrent requests:
|
|
88
|
+
```bash
|
|
89
|
+
vllm serve MODEL --max-num-seqs 512 # Increase from 256
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
2. **Check if memory-bound**:
|
|
93
|
+
```bash
|
|
94
|
+
# If memory at 100% but GPU <80%, reduce sequence length
|
|
95
|
+
vllm serve MODEL --max-model-len 4096
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
3. **Enable optimizations**:
|
|
99
|
+
```bash
|
|
100
|
+
vllm serve MODEL \
|
|
101
|
+
--enable-prefix-caching \
|
|
102
|
+
--enable-chunked-prefill \
|
|
103
|
+
--max-num-seqs 512
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
4. **Check tensor parallelism settings**:
|
|
107
|
+
```bash
|
|
108
|
+
# Must use power-of-2 GPUs
|
|
109
|
+
vllm serve MODEL --tensor-parallel-size 4 # Not 3 or 5
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Symptom: High TTFT (time to first token >1 second)
|
|
113
|
+
|
|
114
|
+
**Causes and solutions**:
|
|
115
|
+
|
|
116
|
+
**Long prompts**:
|
|
117
|
+
```bash
|
|
118
|
+
vllm serve MODEL --enable-chunked-prefill
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
**No prefix caching**:
|
|
122
|
+
```bash
|
|
123
|
+
vllm serve MODEL --enable-prefix-caching # For repeated prompts
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
**Too many concurrent requests**:
|
|
127
|
+
```bash
|
|
128
|
+
vllm serve MODEL --max-num-seqs 64 # Reduce to prioritize latency
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
**Model too large for single GPU**:
|
|
132
|
+
```bash
|
|
133
|
+
vllm serve MODEL --tensor-parallel-size 2 # Parallelize prefill
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Symptom: Slow token generation (low tokens/sec)
|
|
137
|
+
|
|
138
|
+
**Diagnostic**:
|
|
139
|
+
```bash
|
|
140
|
+
# Check if model is correct size
|
|
141
|
+
vllm serve MODEL # Should see model size in logs
|
|
142
|
+
|
|
143
|
+
# Check speculative decoding
|
|
144
|
+
vllm serve MODEL --speculative-model DRAFT_MODEL
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
**For H100 GPUs**, enable FP8:
|
|
148
|
+
```bash
|
|
149
|
+
vllm serve MODEL --quantization fp8
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## Model loading errors
|
|
153
|
+
|
|
154
|
+
### Symptom: `OSError: MODEL not found`
|
|
155
|
+
|
|
156
|
+
**Causes**:
|
|
157
|
+
|
|
158
|
+
1. **Model name typo**:
|
|
159
|
+
```bash
|
|
160
|
+
# Check exact model name on HuggingFace
|
|
161
|
+
vllm serve meta-llama/Llama-3-8B-Instruct # Correct capitalization
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
2. **Private/gated model**:
|
|
165
|
+
```bash
|
|
166
|
+
# Login to HuggingFace first
|
|
167
|
+
huggingface-cli login
|
|
168
|
+
# Then run vLLM
|
|
169
|
+
vllm serve meta-llama/Llama-3-70B-Instruct
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
3. **Custom model needs trust flag**:
|
|
173
|
+
```bash
|
|
174
|
+
vllm serve MODEL --trust-remote-code
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Symptom: `ValueError: Tokenizer not found`
|
|
178
|
+
|
|
179
|
+
**Solution**:
|
|
180
|
+
```bash
|
|
181
|
+
# Download model manually first
|
|
182
|
+
python -c "from transformers import AutoTokenizer; AutoTokenizer.from_pretrained('MODEL')"
|
|
183
|
+
|
|
184
|
+
# Then launch vLLM
|
|
185
|
+
vllm serve MODEL
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### Symptom: `ImportError: No module named 'flash_attn'`
|
|
189
|
+
|
|
190
|
+
**Solution**:
|
|
191
|
+
```bash
|
|
192
|
+
# Install flash attention
|
|
193
|
+
pip install flash-attn --no-build-isolation
|
|
194
|
+
|
|
195
|
+
# Or disable flash attention
|
|
196
|
+
vllm serve MODEL --disable-flash-attn
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
## Network and connection issues
|
|
200
|
+
|
|
201
|
+
### Symptom: `Connection refused` when querying server
|
|
202
|
+
|
|
203
|
+
**Diagnostic**:
|
|
204
|
+
|
|
205
|
+
1. **Check server is running**:
|
|
206
|
+
```bash
|
|
207
|
+
curl http://localhost:8000/health
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
2. **Check port binding**:
|
|
211
|
+
```bash
|
|
212
|
+
# Bind to all interfaces for remote access
|
|
213
|
+
vllm serve MODEL --host 0.0.0.0 --port 8000
|
|
214
|
+
|
|
215
|
+
# Check if port is in use
|
|
216
|
+
lsof -i :8000
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
3. **Check firewall**:
|
|
220
|
+
```bash
|
|
221
|
+
# Allow port through firewall
|
|
222
|
+
sudo ufw allow 8000
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### Symptom: Slow response times over network
|
|
226
|
+
|
|
227
|
+
**Solutions**:
|
|
228
|
+
|
|
229
|
+
1. **Increase timeout**:
|
|
230
|
+
```python
|
|
231
|
+
from openai import OpenAI
|
|
232
|
+
|
|
233
|
+
client = OpenAI(
|
|
234
|
+
base_url="http://localhost:8000/v1",
|
|
235
|
+
api_key="EMPTY",
|
|
236
|
+
timeout=300.0 # 5 minute timeout
|
|
237
|
+
)
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
2. **Check network latency**:
|
|
241
|
+
```bash
|
|
242
|
+
ping SERVER_IP # Should be <10ms for local network
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
3. **Use connection pooling**:
|
|
246
|
+
```python
|
|
247
|
+
import requests
|
|
248
|
+
from requests.adapters import HTTPAdapter
|
|
249
|
+
from urllib3.util.retry import Retry
|
|
250
|
+
|
|
251
|
+
session = requests.Session()
|
|
252
|
+
retries = Retry(total=3, backoff_factor=1)
|
|
253
|
+
session.mount('http://', HTTPAdapter(max_retries=retries))
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
## Quantization problems
|
|
257
|
+
|
|
258
|
+
### Symptom: `RuntimeError: Quantization format not supported`
|
|
259
|
+
|
|
260
|
+
**Solution**:
|
|
261
|
+
```bash
|
|
262
|
+
# Ensure correct quantization method
|
|
263
|
+
vllm serve MODEL --quantization awq # For AWQ models
|
|
264
|
+
vllm serve MODEL --quantization gptq # For GPTQ models
|
|
265
|
+
|
|
266
|
+
# Check model card for quantization type
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
### Symptom: Poor quality outputs after quantization
|
|
270
|
+
|
|
271
|
+
**Diagnostic**:
|
|
272
|
+
|
|
273
|
+
1. **Verify model is correctly quantized**:
|
|
274
|
+
```bash
|
|
275
|
+
# Check model config.json for quantization_config
|
|
276
|
+
cat ~/.cache/huggingface/hub/models--MODEL/config.json
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
2. **Try different quantization method**:
|
|
280
|
+
```bash
|
|
281
|
+
# If AWQ quality issues, try FP8 (H100 only)
|
|
282
|
+
vllm serve MODEL --quantization fp8
|
|
283
|
+
|
|
284
|
+
# Or use less aggressive quantization
|
|
285
|
+
vllm serve MODEL # No quantization
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
3. **Increase temperature for better diversity**:
|
|
289
|
+
```python
|
|
290
|
+
sampling_params = SamplingParams(temperature=0.8, top_p=0.95)
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
## Distributed serving issues
|
|
294
|
+
|
|
295
|
+
### Symptom: `RuntimeError: Distributed init failed`
|
|
296
|
+
|
|
297
|
+
**Diagnostic**:
|
|
298
|
+
|
|
299
|
+
1. **Check environment variables**:
|
|
300
|
+
```bash
|
|
301
|
+
# On all nodes
|
|
302
|
+
echo $MASTER_ADDR # Should be same
|
|
303
|
+
echo $MASTER_PORT # Should be same
|
|
304
|
+
echo $RANK # Should be unique per node (0, 1, 2, ...)
|
|
305
|
+
echo $WORLD_SIZE # Should be same (total nodes)
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
2. **Check network connectivity**:
|
|
309
|
+
```bash
|
|
310
|
+
# From node 1 to node 2
|
|
311
|
+
ping NODE2_IP
|
|
312
|
+
nc -zv NODE2_IP 29500 # Check port accessibility
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
3. **Check NCCL settings**:
|
|
316
|
+
```bash
|
|
317
|
+
export NCCL_DEBUG=INFO
|
|
318
|
+
export NCCL_SOCKET_IFNAME=eth0 # Or your network interface
|
|
319
|
+
vllm serve MODEL --tensor-parallel-size 8
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
### Symptom: `NCCL error: unhandled cuda error`
|
|
323
|
+
|
|
324
|
+
**Solutions**:
|
|
325
|
+
|
|
326
|
+
```bash
|
|
327
|
+
# Set NCCL to use correct network interface
|
|
328
|
+
export NCCL_SOCKET_IFNAME=eth0 # Replace with your interface
|
|
329
|
+
|
|
330
|
+
# Increase timeout
|
|
331
|
+
export NCCL_TIMEOUT=1800 # 30 minutes
|
|
332
|
+
|
|
333
|
+
# Force P2P for debugging
|
|
334
|
+
export NCCL_P2P_DISABLE=1
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
## Debugging tools and commands
|
|
338
|
+
|
|
339
|
+
### Enable debug logging
|
|
340
|
+
|
|
341
|
+
```bash
|
|
342
|
+
export VLLM_LOGGING_LEVEL=DEBUG
|
|
343
|
+
vllm serve MODEL
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
### Monitor GPU usage
|
|
347
|
+
|
|
348
|
+
```bash
|
|
349
|
+
# Real-time GPU monitoring
|
|
350
|
+
watch -n 1 nvidia-smi
|
|
351
|
+
|
|
352
|
+
# Memory breakdown
|
|
353
|
+
nvidia-smi --query-gpu=memory.used,memory.free --format=csv -l 1
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
### Profile performance
|
|
357
|
+
|
|
358
|
+
```bash
|
|
359
|
+
# Built-in benchmarking
|
|
360
|
+
vllm bench throughput \
|
|
361
|
+
--model MODEL \
|
|
362
|
+
--input-tokens 128 \
|
|
363
|
+
--output-tokens 256 \
|
|
364
|
+
--num-prompts 100
|
|
365
|
+
|
|
366
|
+
vllm bench latency \
|
|
367
|
+
--model MODEL \
|
|
368
|
+
--input-tokens 128 \
|
|
369
|
+
--output-tokens 256 \
|
|
370
|
+
--batch-size 8
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
### Check metrics
|
|
374
|
+
|
|
375
|
+
```bash
|
|
376
|
+
# Prometheus metrics
|
|
377
|
+
curl http://localhost:9090/metrics
|
|
378
|
+
|
|
379
|
+
# Filter for specific metrics
|
|
380
|
+
curl http://localhost:9090/metrics | grep vllm_time_to_first_token
|
|
381
|
+
|
|
382
|
+
# Key metrics to monitor:
|
|
383
|
+
# - vllm_time_to_first_token_seconds
|
|
384
|
+
# - vllm_time_per_output_token_seconds
|
|
385
|
+
# - vllm_num_requests_running
|
|
386
|
+
# - vllm_gpu_cache_usage_perc
|
|
387
|
+
# - vllm_request_success_total
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
### Test server health
|
|
391
|
+
|
|
392
|
+
```bash
|
|
393
|
+
# Health check
|
|
394
|
+
curl http://localhost:8000/health
|
|
395
|
+
|
|
396
|
+
# Model info
|
|
397
|
+
curl http://localhost:8000/v1/models
|
|
398
|
+
|
|
399
|
+
# Test completion
|
|
400
|
+
curl http://localhost:8000/v1/completions \
|
|
401
|
+
-H "Content-Type: application/json" \
|
|
402
|
+
-d '{
|
|
403
|
+
"model": "MODEL",
|
|
404
|
+
"prompt": "Hello",
|
|
405
|
+
"max_tokens": 10
|
|
406
|
+
}'
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
### Common environment variables
|
|
410
|
+
|
|
411
|
+
```bash
|
|
412
|
+
# CUDA settings
|
|
413
|
+
export CUDA_VISIBLE_DEVICES=0,1,2,3 # Limit to specific GPUs
|
|
414
|
+
|
|
415
|
+
# vLLM settings
|
|
416
|
+
export VLLM_LOGGING_LEVEL=DEBUG
|
|
417
|
+
export VLLM_TRACE_FUNCTION=1 # Profile functions
|
|
418
|
+
export VLLM_USE_V1=1 # Use v1.0 engine (faster)
|
|
419
|
+
|
|
420
|
+
# NCCL settings (distributed)
|
|
421
|
+
export NCCL_DEBUG=INFO
|
|
422
|
+
export NCCL_SOCKET_IFNAME=eth0
|
|
423
|
+
export NCCL_IB_DISABLE=0 # Enable InfiniBand
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
### Collect diagnostic info for bug reports
|
|
427
|
+
|
|
428
|
+
```bash
|
|
429
|
+
# System info
|
|
430
|
+
nvidia-smi
|
|
431
|
+
python --version
|
|
432
|
+
pip show vllm
|
|
433
|
+
|
|
434
|
+
# vLLM version and config
|
|
435
|
+
vllm --version
|
|
436
|
+
python -c "import vllm; print(vllm.__version__)"
|
|
437
|
+
|
|
438
|
+
# Run with debug logging
|
|
439
|
+
export VLLM_LOGGING_LEVEL=DEBUG
|
|
440
|
+
vllm serve MODEL 2>&1 | tee vllm_debug.log
|
|
441
|
+
|
|
442
|
+
# Include in bug report:
|
|
443
|
+
# - vllm_debug.log
|
|
444
|
+
# - nvidia-smi output
|
|
445
|
+
# - Full command used
|
|
446
|
+
# - Expected vs actual behavior
|
|
447
|
+
```
|
EvoScientist/stream/__init__.py
CHANGED
|
@@ -6,9 +6,6 @@ Provides:
|
|
|
6
6
|
- ToolCallTracker: Incremental JSON parsing for tool parameters
|
|
7
7
|
- ToolResultFormatter: Content-aware result formatting with Rich
|
|
8
8
|
- Utility functions and constants
|
|
9
|
-
- SubAgentState / StreamState: Stream state tracking
|
|
10
|
-
- stream_agent_events: Async event generator
|
|
11
|
-
- Display functions: Rich rendering for streaming and final output
|
|
12
9
|
"""
|
|
13
10
|
|
|
14
11
|
from .emitter import StreamEventEmitter, StreamEvent
|
|
@@ -28,15 +25,6 @@ from .utils import (
|
|
|
28
25
|
truncate_with_line_hint,
|
|
29
26
|
get_status_symbol,
|
|
30
27
|
)
|
|
31
|
-
from .state import SubAgentState, StreamState, _parse_todo_items, _build_todo_stats
|
|
32
|
-
from .events import stream_agent_events
|
|
33
|
-
from .display import (
|
|
34
|
-
console,
|
|
35
|
-
formatter,
|
|
36
|
-
format_tool_result_compact,
|
|
37
|
-
create_streaming_display,
|
|
38
|
-
display_final_results,
|
|
39
|
-
)
|
|
40
28
|
|
|
41
29
|
__all__ = [
|
|
42
30
|
# Emitter
|
|
@@ -62,17 +50,4 @@ __all__ = [
|
|
|
62
50
|
"count_lines",
|
|
63
51
|
"truncate_with_line_hint",
|
|
64
52
|
"get_status_symbol",
|
|
65
|
-
# State
|
|
66
|
-
"SubAgentState",
|
|
67
|
-
"StreamState",
|
|
68
|
-
"_parse_todo_items",
|
|
69
|
-
"_build_todo_stats",
|
|
70
|
-
# Events
|
|
71
|
-
"stream_agent_events",
|
|
72
|
-
# Display
|
|
73
|
-
"console",
|
|
74
|
-
"formatter",
|
|
75
|
-
"format_tool_result_compact",
|
|
76
|
-
"create_streaming_display",
|
|
77
|
-
"display_final_results",
|
|
78
53
|
]
|
EvoScientist/stream/utils.py
CHANGED
|
@@ -114,40 +114,34 @@ def format_tool_compact(name: str, args: dict | None) -> str:
|
|
|
114
114
|
if name_lower == "execute":
|
|
115
115
|
cmd = args.get("command", "")
|
|
116
116
|
if len(cmd) > 50:
|
|
117
|
-
cmd = cmd[:47] + "
|
|
117
|
+
cmd = cmd[:47] + "..."
|
|
118
118
|
return f"execute({cmd})"
|
|
119
119
|
|
|
120
|
-
# File operations
|
|
120
|
+
# File operations
|
|
121
121
|
if name_lower == "read_file":
|
|
122
|
-
path = args.get("path", "")
|
|
123
|
-
|
|
124
|
-
return "Reading memory"
|
|
125
|
-
return f"read_file({_shorten_path(path)})"
|
|
122
|
+
path = _shorten_path(args.get("path", ""))
|
|
123
|
+
return f"read_file({path})"
|
|
126
124
|
|
|
127
125
|
if name_lower == "write_file":
|
|
128
|
-
path = args.get("path", "")
|
|
129
|
-
|
|
130
|
-
return "Updating memory"
|
|
131
|
-
return f"write_file({_shorten_path(path)})"
|
|
126
|
+
path = _shorten_path(args.get("path", ""))
|
|
127
|
+
return f"write_file({path})"
|
|
132
128
|
|
|
133
129
|
if name_lower == "edit_file":
|
|
134
|
-
path = args.get("path", "")
|
|
135
|
-
|
|
136
|
-
return "Updating memory"
|
|
137
|
-
return f"edit_file({_shorten_path(path)})"
|
|
130
|
+
path = _shorten_path(args.get("path", ""))
|
|
131
|
+
return f"edit_file({path})"
|
|
138
132
|
|
|
139
133
|
# Search operations
|
|
140
134
|
if name_lower == "glob":
|
|
141
135
|
pattern = args.get("pattern", "")
|
|
142
136
|
if len(pattern) > 40:
|
|
143
|
-
pattern = pattern[:37] + "
|
|
137
|
+
pattern = pattern[:37] + "..."
|
|
144
138
|
return f"glob({pattern})"
|
|
145
139
|
|
|
146
140
|
if name_lower == "grep":
|
|
147
141
|
pattern = args.get("pattern", "")
|
|
148
142
|
path = args.get("path", ".")
|
|
149
143
|
if len(pattern) > 30:
|
|
150
|
-
pattern = pattern[:27] + "
|
|
144
|
+
pattern = pattern[:27] + "..."
|
|
151
145
|
return f"grep({pattern}, {path})"
|
|
152
146
|
|
|
153
147
|
# Directory listing
|
|
@@ -169,17 +163,16 @@ def format_tool_compact(name: str, args: dict | None) -> str:
|
|
|
169
163
|
if name_lower == "task":
|
|
170
164
|
sa_type = args.get("subagent_type", "").strip()
|
|
171
165
|
task_desc = args.get("description", args.get("task", "")).strip()
|
|
172
|
-
task_desc = task_desc.split("\n")[0].strip() if task_desc else ""
|
|
173
166
|
if sa_type:
|
|
174
167
|
if task_desc:
|
|
175
168
|
if len(task_desc) > 50:
|
|
176
|
-
task_desc = task_desc[:47] + "
|
|
169
|
+
task_desc = task_desc[:47] + "..."
|
|
177
170
|
return f"Cooking with {sa_type} — {task_desc}"
|
|
178
171
|
return f"Cooking with {sa_type}"
|
|
179
172
|
# Fallback if no subagent_type
|
|
180
173
|
if task_desc:
|
|
181
174
|
if len(task_desc) > 50:
|
|
182
|
-
task_desc = task_desc[:47] + "
|
|
175
|
+
task_desc = task_desc[:47] + "..."
|
|
183
176
|
return f"Cooking with sub-agent — {task_desc}"
|
|
184
177
|
return "Cooking with sub-agent"
|
|
185
178
|
|
|
@@ -192,14 +185,14 @@ def format_tool_compact(name: str, args: dict | None) -> str:
|
|
|
192
185
|
if name_lower in ("tavily_search", "internet_search"):
|
|
193
186
|
query = args.get("query", "")
|
|
194
187
|
if len(query) > 40:
|
|
195
|
-
query = query[:37] + "
|
|
188
|
+
query = query[:37] + "..."
|
|
196
189
|
return f"{name}({query})"
|
|
197
190
|
|
|
198
191
|
# Think/reflection
|
|
199
192
|
if name_lower == "think_tool":
|
|
200
193
|
reflection = args.get("reflection", "")
|
|
201
194
|
if len(reflection) > 40:
|
|
202
|
-
reflection = reflection[:37] + "
|
|
195
|
+
reflection = reflection[:37] + "..."
|
|
203
196
|
return f"think_tool({reflection})"
|
|
204
197
|
|
|
205
198
|
# Default: show first few params
|
|
@@ -207,12 +200,12 @@ def format_tool_compact(name: str, args: dict | None) -> str:
|
|
|
207
200
|
for k, v in list(args.items())[:2]:
|
|
208
201
|
v_str = str(v)
|
|
209
202
|
if len(v_str) > 20:
|
|
210
|
-
v_str = v_str[:17] + "
|
|
203
|
+
v_str = v_str[:17] + "..."
|
|
211
204
|
params.append(f"{k}={v_str}")
|
|
212
205
|
|
|
213
206
|
params_str = ", ".join(params)
|
|
214
207
|
if len(params_str) > 50:
|
|
215
|
-
params_str = params_str[:47] + "
|
|
208
|
+
params_str = params_str[:47] + "..."
|
|
216
209
|
|
|
217
210
|
return f"{name}({params_str})"
|
|
218
211
|
|
EvoScientist/tools.py
CHANGED
|
@@ -16,16 +16,7 @@ from typing_extensions import Annotated
|
|
|
16
16
|
|
|
17
17
|
load_dotenv(override=True)
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
_tavily_client = None
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
def _get_tavily_client() -> TavilyClient:
|
|
24
|
-
"""Get or create the Tavily client (lazy initialization)."""
|
|
25
|
-
global _tavily_client
|
|
26
|
-
if _tavily_client is None:
|
|
27
|
-
_tavily_client = TavilyClient()
|
|
28
|
-
return _tavily_client
|
|
19
|
+
tavily_client = TavilyClient()
|
|
29
20
|
|
|
30
21
|
|
|
31
22
|
async def fetch_webpage_content(url: str, timeout: float = 10.0) -> str:
|
|
@@ -76,7 +67,7 @@ async def tavily_search(
|
|
|
76
67
|
"""
|
|
77
68
|
|
|
78
69
|
def _sync_search() -> dict:
|
|
79
|
-
return
|
|
70
|
+
return tavily_client.search(
|
|
80
71
|
query,
|
|
81
72
|
max_results=max_results,
|
|
82
73
|
topic=topic,
|
|
@@ -115,70 +106,6 @@ async def tavily_search(
|
|
|
115
106
|
return f"Search failed: {str(e)}"
|
|
116
107
|
|
|
117
108
|
|
|
118
|
-
@tool(parse_docstring=True)
|
|
119
|
-
def skill_manager(
|
|
120
|
-
action: Literal["install", "list", "uninstall"],
|
|
121
|
-
source: str = "",
|
|
122
|
-
name: str = "",
|
|
123
|
-
) -> str:
|
|
124
|
-
"""Manage user skills: install, list, or uninstall.
|
|
125
|
-
|
|
126
|
-
Use this tool when the user asks to:
|
|
127
|
-
- Install a skill (action="install", source required)
|
|
128
|
-
- List installed skills (action="list")
|
|
129
|
-
- Uninstall a skill (action="uninstall", name required)
|
|
130
|
-
|
|
131
|
-
Supported sources for install:
|
|
132
|
-
- Local path: "./my-skill" or "/path/to/skill"
|
|
133
|
-
- GitHub URL: "https://github.com/owner/repo/tree/main/skill-name"
|
|
134
|
-
- GitHub shorthand: "owner/repo@skill-name"
|
|
135
|
-
|
|
136
|
-
Args:
|
|
137
|
-
action: One of "install", "list", or "uninstall"
|
|
138
|
-
source: For install - local path or GitHub URL/shorthand
|
|
139
|
-
name: For uninstall - skill name to remove
|
|
140
|
-
|
|
141
|
-
Returns:
|
|
142
|
-
Result message
|
|
143
|
-
"""
|
|
144
|
-
from .skills_manager import install_skill, list_skills, uninstall_skill
|
|
145
|
-
|
|
146
|
-
if action == "install":
|
|
147
|
-
if not source:
|
|
148
|
-
return "Error: 'source' is required for install action"
|
|
149
|
-
result = install_skill(source)
|
|
150
|
-
if result["success"]:
|
|
151
|
-
return (
|
|
152
|
-
f"Successfully installed skill: {result['name']}\n"
|
|
153
|
-
f"Description: {result.get('description', '(none)')}\n"
|
|
154
|
-
f"Path: {result['path']}\n\n"
|
|
155
|
-
f"Use load_skill to activate it."
|
|
156
|
-
)
|
|
157
|
-
else:
|
|
158
|
-
return f"Failed to install skill: {result['error']}"
|
|
159
|
-
|
|
160
|
-
elif action == "list":
|
|
161
|
-
skills = list_skills(include_system=False)
|
|
162
|
-
if not skills:
|
|
163
|
-
return "No user skills installed. Use action='install' to add skills."
|
|
164
|
-
lines = [f"Installed User Skills ({len(skills)}):"]
|
|
165
|
-
for skill in skills:
|
|
166
|
-
lines.append(f" - {skill.name}: {skill.description}")
|
|
167
|
-
return "\n".join(lines)
|
|
168
|
-
|
|
169
|
-
elif action == "uninstall":
|
|
170
|
-
if not name:
|
|
171
|
-
return "Error: 'name' is required for uninstall action"
|
|
172
|
-
result = uninstall_skill(name)
|
|
173
|
-
if result["success"]:
|
|
174
|
-
return f"Successfully uninstalled skill: {name}"
|
|
175
|
-
else:
|
|
176
|
-
return f"Failed to uninstall skill: {result['error']}"
|
|
177
|
-
|
|
178
|
-
else:
|
|
179
|
-
return f"Unknown action: {action}. Use 'install', 'list', or 'uninstall'."
|
|
180
|
-
|
|
181
|
-
|
|
182
109
|
@tool(parse_docstring=True)
|
|
183
110
|
def think_tool(reflection: str) -> str:
|
|
184
111
|
"""Tool for strategic reflection on research progress and decision-making.
|