wafer-cli 0.2.61__tar.gz → 0.2.63__tar.gz

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.
Files changed (96) hide show
  1. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/PKG-INFO +1 -1
  2. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/pyproject.toml +1 -1
  3. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/tests/test_corpus_lockdown.py +3 -4
  4. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/tests/test_direct_streaming.py +126 -0
  5. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/wafer/wevin_cli.py +39 -1
  6. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/wafer_cli.egg-info/PKG-INFO +1 -1
  7. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/README.md +0 -0
  8. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/setup.cfg +0 -0
  9. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/tests/test_agent_template_discovery.py +0 -0
  10. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/tests/test_analytics.py +0 -0
  11. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/tests/test_auth.py +0 -0
  12. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/tests/test_billing.py +0 -0
  13. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/tests/test_cli_coverage.py +0 -0
  14. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/tests/test_cli_parity_integration.py +0 -0
  15. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/tests/test_config_show.py +0 -0
  16. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/tests/test_deps.py +0 -0
  17. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/tests/test_distributed_traces_cli.py +0 -0
  18. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/tests/test_docker_progress.py +0 -0
  19. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/tests/test_evaluate_ux.py +0 -0
  20. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/tests/test_file_operations_integration.py +0 -0
  21. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/tests/test_first_run.py +0 -0
  22. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/tests/test_inference.py +0 -0
  23. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/tests/test_json_output.py +0 -0
  24. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/tests/test_kernel_scope_cli.py +0 -0
  25. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/tests/test_ncu_run.py +0 -0
  26. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/tests/test_ncu_run_e2e.py +0 -0
  27. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/tests/test_ncu_run_local_e2e.py +0 -0
  28. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/tests/test_nsys_analyze.py +0 -0
  29. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/tests/test_nsys_profile.py +0 -0
  30. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/tests/test_output.py +0 -0
  31. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/tests/test_rocprof_compute_integration.py +0 -0
  32. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/tests/test_skill_commands.py +0 -0
  33. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/tests/test_ssh_integration.py +0 -0
  34. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/tests/test_status.py +0 -0
  35. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/tests/test_targets_ops.py +0 -0
  36. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/tests/test_token_waste.py +0 -0
  37. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/tests/test_ux_improvements.py +0 -0
  38. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/tests/test_wevin_cli.py +0 -0
  39. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/wafer/GUIDE.md +0 -0
  40. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/wafer/__init__.py +0 -0
  41. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/wafer/agent_defaults.py +0 -0
  42. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/wafer/analytics.py +0 -0
  43. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/wafer/api_client.py +0 -0
  44. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/wafer/auth.py +0 -0
  45. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/wafer/autotuner.py +0 -0
  46. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/wafer/baseline.py +0 -0
  47. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/wafer/billing.py +0 -0
  48. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/wafer/cli.py +0 -0
  49. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/wafer/cli_instructions.py +0 -0
  50. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/wafer/deps.py +0 -0
  51. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/wafer/distributed_traces.py +0 -0
  52. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/wafer/evaluate.py +0 -0
  53. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/wafer/global_config.py +0 -0
  54. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/wafer/gpu_run.py +0 -0
  55. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/wafer/inference.py +0 -0
  56. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/wafer/kernel_scope.py +0 -0
  57. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/wafer/ncu_analyze.py +0 -0
  58. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/wafer/ncu_run.py +0 -0
  59. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/wafer/nsys_analyze.py +0 -0
  60. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/wafer/nsys_profile.py +0 -0
  61. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/wafer/output.py +0 -0
  62. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/wafer/problems.py +0 -0
  63. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/wafer/rocprof_compute.py +0 -0
  64. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/wafer/rocprof_sdk.py +0 -0
  65. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/wafer/rocprof_systems.py +0 -0
  66. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/wafer/skills/packed-ops-guide/SKILL.md +0 -0
  67. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/wafer/skills/wafer-guide/SKILL.md +0 -0
  68. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/wafer/skills/wafer-guide/commands.md +0 -0
  69. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/wafer/skills/wafer-guide/evaluate.md +0 -0
  70. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/wafer/skills/wafer-guide/pitfalls.md +0 -0
  71. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/wafer/skills/wafer-guide/profiling.md +0 -0
  72. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/wafer/skills/wafer-guide/workspaces.md +0 -0
  73. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/wafer/specs_cli.py +0 -0
  74. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/wafer/ssh_keys.py +0 -0
  75. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/wafer/target_lock.py +0 -0
  76. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/wafer/targets.py +0 -0
  77. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/wafer/targets_cli.py +0 -0
  78. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/wafer/targets_ops.py +0 -0
  79. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/wafer/templates/__init__.py +0 -0
  80. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/wafer/templates/aiter_optimize.py +0 -0
  81. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/wafer/templates/ask_docs.py +0 -0
  82. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/wafer/templates/audit.py +0 -0
  83. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/wafer/templates/optimize_flashinfer.py +0 -0
  84. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/wafer/templates/optimize_kernel.py +0 -0
  85. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/wafer/templates/optimize_kernelbench.py +0 -0
  86. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/wafer/templates/optimize_vllm.py +0 -0
  87. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/wafer/templates/trace_analyze.py +0 -0
  88. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/wafer/tests/test_eval_cli_parity.py +0 -0
  89. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/wafer/trace_compare.py +0 -0
  90. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/wafer/tracelens.py +0 -0
  91. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/wafer/workspaces.py +0 -0
  92. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/wafer_cli.egg-info/SOURCES.txt +0 -0
  93. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/wafer_cli.egg-info/dependency_links.txt +0 -0
  94. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/wafer_cli.egg-info/entry_points.txt +0 -0
  95. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/wafer_cli.egg-info/requires.txt +0 -0
  96. {wafer_cli-0.2.61 → wafer_cli-0.2.63}/wafer_cli.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wafer-cli
3
- Version: 0.2.61
3
+ Version: 0.2.63
4
4
  Summary: CLI for running GPU workloads, managing remote workspaces, and evaluating/optimizing kernels
5
5
  Requires-Python: >=3.11
6
6
  Description-Content-Type: text/markdown
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "wafer-cli"
3
- version = "0.2.61"
3
+ version = "0.2.63"
4
4
  description = "CLI for running GPU workloads, managing remote workspaces, and evaluating/optimizing kernels"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -66,13 +66,12 @@ class TestCorpusModuleRemoved:
66
66
  class TestNoCorpusPathsInTemplates:
67
67
  """Templates should not reference local corpus paths."""
68
68
 
69
- def test_ask_docs_template_uses_ask_docs_tool(self) -> None:
69
+ def test_ask_docs_template_uses_direct_endpoint(self) -> None:
70
+ """ask-docs streams from server via direct_endpoint — no local agent, no local corpus."""
70
71
  from wafer_core.rollouts.templates.loader import load_template
71
72
  bundled = Path(__file__).parent.parent / "wafer" / "templates"
72
73
  config = load_template("ask-docs", search_paths=[bundled])
73
- assert "ask_docs" in config.tools
74
- assert "bash" not in config.tools
75
- assert "glob" not in config.tools
74
+ assert config.direct_endpoint == "/v1/docs/query"
76
75
 
77
76
  def test_no_corpus_path_in_ask_docs_prompt(self) -> None:
78
77
  from wafer_core.rollouts.templates.loader import load_template
@@ -274,6 +274,7 @@ class TestStreamDirectEndpoint:
274
274
 
275
275
  def test_json_mode_tool_events(self) -> None:
276
276
  events = [
277
+ {"type": "tool_call_start", "name": "grep"},
277
278
  {"type": "tool_call", "name": "grep", "input": {"pattern": "warp"}},
278
279
  {"type": "tool_result", "name": "grep", "content": "line1\n"},
279
280
  {"type": "text", "content": "Answer"},
@@ -287,6 +288,8 @@ class TestStreamDirectEndpoint:
287
288
  assert "tool_result" in types
288
289
  assert "text_delta" in types
289
290
  assert "session_end" in types
291
+ # Exactly one tool_call_start (from tool_call_start event, not duplicated by tool_call event)
292
+ assert types.count("tool_call_start") == 1
290
293
 
291
294
  def test_json_mode_error_event(self) -> None:
292
295
  events = [
@@ -350,3 +353,126 @@ class TestStreamDirectEndpoint:
350
353
  assert "grep" in stderr_text
351
354
  assert "reading" in stderr_text
352
355
  assert any("Final answer." in s for s in stdout)
356
+
357
+ def test_sources_event_renders_to_stderr(self) -> None:
358
+ events = [
359
+ {"type": "text", "content": "Answer here."},
360
+ {"type": "sources", "files": ["./memory.md", "./guide.md"]},
361
+ {"type": "done"},
362
+ ]
363
+ _, _, stderr = self._run(events)
364
+ stderr_text = " ".join(stderr)
365
+ assert "Sources" in stderr_text
366
+ assert "./memory.md" in stderr_text
367
+ assert "./guide.md" in stderr_text
368
+
369
+ def test_json_mode_sources_event(self) -> None:
370
+ events = [
371
+ {"type": "text", "content": "Answer"},
372
+ {"type": "sources", "files": ["./memory.md"]},
373
+ {"type": "done"},
374
+ ]
375
+ _, stdout, _ = self._run(events, json_output=True)
376
+ json_events = [json.loads(line) for line in stdout if line.strip()]
377
+ sources_events = [e for e in json_events if e.get("type") == "sources"]
378
+ assert len(sources_events) == 1
379
+ assert sources_events[0]["files"] == ["./memory.md"]
380
+
381
+ def test_turn_start_renders_to_stderr(self) -> None:
382
+ """turn_start event should print turn number to stderr."""
383
+ events = [
384
+ {"type": "turn_start", "turn": 1, "max_turns": 10},
385
+ {"type": "text", "content": "Answer."},
386
+ {"type": "done"},
387
+ ]
388
+ _, _, stderr = self._run(events)
389
+ stderr_text = " ".join(stderr)
390
+ assert "[Turn 1]" in stderr_text
391
+ assert "Searching documentation" in stderr_text
392
+
393
+ def test_tool_call_start_renders_to_stderr(self) -> None:
394
+ """tool_call_start event should print tool name to stderr."""
395
+ events = [
396
+ {"type": "turn_start", "turn": 1, "max_turns": 10},
397
+ {"type": "tool_call_start", "name": "grep"},
398
+ {"type": "tool_call", "name": "grep", "input": {"pattern": "test"}},
399
+ {"type": "tool_exec_start", "name": "grep", "index": 1, "total": 1},
400
+ {"type": "tool_result", "name": "grep", "content": "match\n"},
401
+ {"type": "text", "content": "Answer."},
402
+ {"type": "done"},
403
+ ]
404
+ _, _, stderr = self._run(events)
405
+ stderr_text = " ".join(stderr)
406
+ assert "Calling grep" in stderr_text
407
+
408
+ def test_tool_exec_start_renders_to_stderr(self) -> None:
409
+ """tool_exec_start event should print tool execution progress to stderr."""
410
+ events = [
411
+ {"type": "turn_start", "turn": 1, "max_turns": 10},
412
+ {"type": "tool_call_start", "name": "grep"},
413
+ {"type": "tool_call", "name": "grep", "input": {"pattern": "test"}},
414
+ {"type": "tool_exec_start", "name": "grep", "index": 2, "total": 5},
415
+ {"type": "tool_result", "name": "grep", "content": "match\n"},
416
+ {"type": "text", "content": "Answer."},
417
+ {"type": "done"},
418
+ ]
419
+ _, _, stderr = self._run(events)
420
+ stderr_text = " ".join(stderr)
421
+ assert "Executing grep (2/5)" in stderr_text
422
+
423
+ def test_turn_start_json_mode(self) -> None:
424
+ """turn_start in JSON mode should emit a status event."""
425
+ events = [
426
+ {"type": "turn_start", "turn": 1, "max_turns": 10},
427
+ {"type": "text", "content": "Answer"},
428
+ {"type": "done"},
429
+ ]
430
+ _, stdout, _ = self._run(events, json_output=True)
431
+ json_events = [json.loads(line) for line in stdout if line.strip()]
432
+ status_events = [e for e in json_events if e.get("type") == "status"]
433
+ assert len(status_events) == 1
434
+ assert "Turn 1/10" in status_events[0]["message"]
435
+
436
+ def test_tool_exec_start_json_mode(self) -> None:
437
+ """tool_exec_start in JSON mode should emit a tool_exec_start event."""
438
+ events = [
439
+ {"type": "turn_start", "turn": 1, "max_turns": 10},
440
+ {"type": "tool_call_start", "name": "grep"},
441
+ {"type": "tool_call", "name": "grep", "input": {"pattern": "test"}},
442
+ {"type": "tool_exec_start", "name": "grep", "index": 1, "total": 3},
443
+ {"type": "tool_result", "name": "grep", "content": "match\n"},
444
+ {"type": "text", "content": "Answer"},
445
+ {"type": "done"},
446
+ ]
447
+ _, stdout, _ = self._run(events, json_output=True)
448
+ json_events = [json.loads(line) for line in stdout if line.strip()]
449
+ exec_events = [e for e in json_events if e.get("type") == "tool_exec_start"]
450
+ assert len(exec_events) == 1
451
+ assert exec_events[0]["tool_name"] == "grep"
452
+ assert exec_events[0]["index"] == 1
453
+ assert exec_events[0]["total"] == 3
454
+
455
+ def test_full_progress_sequence(self) -> None:
456
+ """Full event sequence renders all progress lines in correct order."""
457
+ events = [
458
+ {"type": "turn_start", "turn": 1, "max_turns": 10},
459
+ {"type": "tool_call_start", "name": "grep"},
460
+ {"type": "tool_call", "name": "grep", "input": {"pattern": "bank conflict"}},
461
+ {"type": "tool_exec_start", "name": "grep", "index": 1, "total": 2},
462
+ {"type": "tool_result", "name": "grep", "content": "file.md:10:bank conflict\n"},
463
+ {"type": "tool_call_start", "name": "read_file"},
464
+ {"type": "tool_call", "name": "read_file", "input": {"path": "./file.md"}},
465
+ {"type": "tool_exec_start", "name": "read_file", "index": 2, "total": 2},
466
+ {"type": "tool_result", "name": "read_file", "content": "Full content here\n"},
467
+ {"type": "turn_start", "turn": 2, "max_turns": 10},
468
+ {"type": "text", "content": "Final answer."},
469
+ {"type": "done"},
470
+ ]
471
+ _, stdout, stderr = self._run(events)
472
+ stderr_text = " ".join(stderr)
473
+ assert "[Turn 1]" in stderr_text
474
+ assert "Calling grep" in stderr_text
475
+ assert "Executing grep (1/2)" in stderr_text
476
+ assert "Executing read_file (2/2)" in stderr_text
477
+ assert "[Turn 2]" in stderr_text
478
+ assert any("Final answer." in s for s in stdout)
@@ -492,7 +492,7 @@ async def _stream_direct_endpoint(
492
492
  summary = _format_tool_call_summary(tool_name, tool_input)
493
493
  if json_output:
494
494
  assert frontend is not None
495
- frontend._emit({"type": "tool_call_start", "tool_name": tool_name})
495
+ # tool_call_start already emitted by the tool_call_start event handler
496
496
  frontend._emit({"type": "tool_call_end", "tool_name": tool_name, "args": tool_input})
497
497
  else:
498
498
  print(f"\033[2m {summary}\033[0m", file=sys.stderr)
@@ -523,6 +523,44 @@ async def _stream_direct_endpoint(
523
523
  else:
524
524
  print(f"\nError: {error_msg}", file=sys.stderr)
525
525
 
526
+ elif event_type == "turn_start":
527
+ turn_num = event.get("turn", "?")
528
+ max_turns = event.get("max_turns", "?")
529
+ if json_output:
530
+ assert frontend is not None
531
+ frontend._emit({"type": "status", "message": f"Turn {turn_num}/{max_turns}"})
532
+ else:
533
+ print(f"\033[2m [Turn {turn_num}] Searching documentation...\033[0m", file=sys.stderr)
534
+
535
+ elif event_type == "tool_call_start":
536
+ tool_name = event.get("name", "")
537
+ if json_output:
538
+ assert frontend is not None
539
+ frontend._emit({"type": "tool_call_start", "tool_name": tool_name})
540
+ else:
541
+ print(f"\033[2m Calling {tool_name}...\033[0m", file=sys.stderr)
542
+
543
+ elif event_type == "tool_exec_start":
544
+ tool_name = event.get("name", "")
545
+ index = event.get("index", "?")
546
+ total = event.get("total", "?")
547
+ if json_output:
548
+ assert frontend is not None
549
+ frontend._emit({"type": "tool_exec_start", "tool_name": tool_name, "index": index, "total": total})
550
+ else:
551
+ print(f"\033[2m Executing {tool_name} ({index}/{total})...\033[0m", file=sys.stderr)
552
+
553
+ elif event_type == "sources":
554
+ files = event.get("files", [])
555
+ if json_output:
556
+ assert frontend is not None
557
+ frontend._emit({"type": "sources", "files": files})
558
+ else:
559
+ if files:
560
+ print(f"\033[2m Sources:\033[0m", file=sys.stderr)
561
+ for f in files:
562
+ print(f"\033[2m {f}\033[0m", file=sys.stderr)
563
+
526
564
  elif event_type == "done":
527
565
  break
528
566
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wafer-cli
3
- Version: 0.2.61
3
+ Version: 0.2.63
4
4
  Summary: CLI for running GPU workloads, managing remote workspaces, and evaluating/optimizing kernels
5
5
  Requires-Python: >=3.11
6
6
  Description-Content-Type: text/markdown
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes