wafer-core 0.1.24__py3-none-any.whl → 0.1.25__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.
- wafer_core/environments/coding.py +0 -4
- wafer_core/rollouts/upload.py +45 -0
- wafer_core/tools/__init__.py +0 -7
- {wafer_core-0.1.24.dist-info → wafer_core-0.1.25.dist-info}/METADATA +1 -1
- {wafer_core-0.1.24.dist-info → wafer_core-0.1.25.dist-info}/RECORD +6 -7
- wafer_core/tools/search_docs_tool.py +0 -196
- {wafer_core-0.1.24.dist-info → wafer_core-0.1.25.dist-info}/WHEEL +0 -0
|
@@ -34,7 +34,6 @@ from wafer_core.tools import (
|
|
|
34
34
|
GLOB_TOOL,
|
|
35
35
|
GREP_TOOL,
|
|
36
36
|
READ_TOOL,
|
|
37
|
-
SEARCH_DOCS_TOOL,
|
|
38
37
|
SKILL_TOOL,
|
|
39
38
|
WRITE_TOOL,
|
|
40
39
|
ApprovalCallback,
|
|
@@ -43,7 +42,6 @@ from wafer_core.tools import (
|
|
|
43
42
|
exec_glob,
|
|
44
43
|
exec_grep,
|
|
45
44
|
exec_read,
|
|
46
|
-
exec_search_docs,
|
|
47
45
|
exec_skill,
|
|
48
46
|
exec_write,
|
|
49
47
|
)
|
|
@@ -65,7 +63,6 @@ ALL_TOOLS = {
|
|
|
65
63
|
"glob": GLOB_TOOL,
|
|
66
64
|
"grep": GREP_TOOL,
|
|
67
65
|
"bash": BASH_TOOL,
|
|
68
|
-
"search_docs": SEARCH_DOCS_TOOL,
|
|
69
66
|
"skill": SKILL_TOOL,
|
|
70
67
|
# TODO(wafer-tool): "wafer": WAFER_TOOL,
|
|
71
68
|
}
|
|
@@ -214,7 +211,6 @@ class CodingEnvironment:
|
|
|
214
211
|
self.bash_approval_callback,
|
|
215
212
|
self._sandbox_policy,
|
|
216
213
|
),
|
|
217
|
-
"search_docs": lambda tc: exec_search_docs(tc),
|
|
218
214
|
"skill": lambda tc: exec_skill(tc),
|
|
219
215
|
# TODO(wafer-tool): "wafer": lambda tc: exec_wafer(
|
|
220
216
|
# tc, self.working_dir, self.enabled_tools, self.allow_spawn, cancel_scope
|
wafer_core/rollouts/upload.py
CHANGED
|
@@ -7,10 +7,13 @@ import logging
|
|
|
7
7
|
import os
|
|
8
8
|
from pathlib import Path
|
|
9
9
|
|
|
10
|
+
import httpx
|
|
11
|
+
|
|
10
12
|
logger = logging.getLogger(__name__)
|
|
11
13
|
|
|
12
14
|
SUPABASE_URL = "https://hvlpthcnxlywlquiciqe.supabase.co"
|
|
13
15
|
BUCKET_NAME = "traces"
|
|
16
|
+
API_BASE = os.environ.get("WAFER_API_URL", "https://api.wafer.ai")
|
|
14
17
|
|
|
15
18
|
|
|
16
19
|
def upload_results_to_supabase(output_dir: Path, log: logging.Logger | None = None) -> bool:
|
|
@@ -95,6 +98,12 @@ def upload_results_to_supabase(output_dir: Path, log: logging.Logger | None = No
|
|
|
95
98
|
)
|
|
96
99
|
|
|
97
100
|
log.info(f"Uploaded {len(uploaded)} files to Supabase: {run_name}")
|
|
101
|
+
|
|
102
|
+
# Auto-index in database for trace viewer
|
|
103
|
+
# Fail if indexing fails - user can re-run (everything is idempotent)
|
|
104
|
+
if not _index_run_in_database(run_name, report_path, log):
|
|
105
|
+
return False
|
|
106
|
+
|
|
98
107
|
return True
|
|
99
108
|
|
|
100
109
|
except ImportError:
|
|
@@ -103,3 +112,39 @@ def upload_results_to_supabase(output_dir: Path, log: logging.Logger | None = No
|
|
|
103
112
|
except Exception as e:
|
|
104
113
|
log.error(f"Failed to upload to Supabase: {e}")
|
|
105
114
|
return False
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def _index_run_in_database(run_name: str, report_path: Path, log: logging.Logger) -> bool:
|
|
118
|
+
"""Index a run in the trace_runs database table for fast querying.
|
|
119
|
+
|
|
120
|
+
Calls POST /v1/eval-traces/runs to upsert the run metadata.
|
|
121
|
+
This enables the trace viewer to show the run immediately without manual sync.
|
|
122
|
+
|
|
123
|
+
Args:
|
|
124
|
+
run_name: Name of the run (folder name)
|
|
125
|
+
report_path: Path to the report.json file
|
|
126
|
+
log: Logger instance
|
|
127
|
+
|
|
128
|
+
Returns:
|
|
129
|
+
True if indexing succeeded, False otherwise
|
|
130
|
+
"""
|
|
131
|
+
try:
|
|
132
|
+
with open(report_path) as f:
|
|
133
|
+
report = json.load(f)
|
|
134
|
+
|
|
135
|
+
response = httpx.post(
|
|
136
|
+
f"{API_BASE}/v1/eval-traces/runs",
|
|
137
|
+
json={"name": run_name, "report": report},
|
|
138
|
+
timeout=30.0,
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
if response.status_code == 200:
|
|
142
|
+
log.info(f"Indexed run in database: {run_name}")
|
|
143
|
+
return True
|
|
144
|
+
else:
|
|
145
|
+
log.error(f"Failed to index run {run_name}: {response.status_code} {response.text}")
|
|
146
|
+
return False
|
|
147
|
+
|
|
148
|
+
except Exception as e:
|
|
149
|
+
log.error(f"Failed to index run {run_name} in database: {e}")
|
|
150
|
+
return False
|
wafer_core/tools/__init__.py
CHANGED
|
@@ -72,10 +72,6 @@ from wafer_core.tools.write_kernel_tool import (
|
|
|
72
72
|
KernelSubmission,
|
|
73
73
|
exec_write_kernel,
|
|
74
74
|
)
|
|
75
|
-
from wafer_core.tools.search_docs_tool import (
|
|
76
|
-
SEARCH_DOCS_TOOL,
|
|
77
|
-
exec_search_docs,
|
|
78
|
-
)
|
|
79
75
|
|
|
80
76
|
__all__ = [
|
|
81
77
|
# File tools
|
|
@@ -137,7 +133,4 @@ __all__ = [
|
|
|
137
133
|
"exec_tracelens_report",
|
|
138
134
|
"exec_tracelens_compare",
|
|
139
135
|
"exec_tracelens_collective",
|
|
140
|
-
# Search docs tool
|
|
141
|
-
"SEARCH_DOCS_TOOL",
|
|
142
|
-
"exec_search_docs",
|
|
143
136
|
]
|
|
@@ -12,7 +12,7 @@ wafer_core/config/__init__.py,sha256=hKywfjA4YXd4lBeBFEcBoMwFoflPHJTiBnkTq7_JYOQ
|
|
|
12
12
|
wafer_core/config/loader.py,sha256=k7JnILmO13TWUzIv9Lm8fvmj3UfYHZDgaFurjQ-GXpY,6623
|
|
13
13
|
wafer_core/config/schema.py,sha256=2WhFlnG0VYYX4T-70BLeJK8Janvi4KEa8KKGZA7331w,3898
|
|
14
14
|
wafer_core/environments/__init__.py,sha256=SIsResVtm22tr_d-oHPeeSxrkhFdmPOFico3DqtRqK8,238
|
|
15
|
-
wafer_core/environments/coding.py,sha256=
|
|
15
|
+
wafer_core/environments/coding.py,sha256=T-_JFU-n5OxPR8xAWp8qar4Y5xyC-TWTIBjRy4PDel8,8418
|
|
16
16
|
wafer_core/environments/gpumode.py,sha256=8Da08nltvN_YloNyYI6-omN2D4n5C7aptKDCtUgT2bQ,17191
|
|
17
17
|
wafer_core/lib/__init__.py,sha256=4-4p3mhwlquejWGglYXU8_nHdA0LoPaa_jGzcm13USA,1325
|
|
18
18
|
wafer_core/lib/kernel_scope/__init__.py,sha256=WW2vu8jUlqOu-MCpgO40lIYacCA9N2u-uuECIs_JO2w,2817
|
|
@@ -359,7 +359,7 @@ wafer_core/rollouts/skills.py,sha256=ATYoG02Cc6_VrtE415TnseBFJrKOMq27z-5YgBgPpZQ
|
|
|
359
359
|
wafer_core/rollouts/slice.py,sha256=darOZO53BuSPfvv_KjOSzulGVSWbL4OuoE3k6xXpBFg,20195
|
|
360
360
|
wafer_core/rollouts/store.py,sha256=UDP9idDOEVs_0Pslx0K_Y8E1i-BeoqVSaxdQiaqtz1E,18051
|
|
361
361
|
wafer_core/rollouts/transform_messages.py,sha256=yldzdLgugNYb5Zxju7myFBel1tmrHXx9M399ImqPLGI,20891
|
|
362
|
-
wafer_core/rollouts/upload.py,sha256=
|
|
362
|
+
wafer_core/rollouts/upload.py,sha256=hEqZfwgb0b4GYbrwRSA3fuqF70pqo6hyaQU59j3vM7E,4890
|
|
363
363
|
wafer_core/rollouts/_logging/__init__.py,sha256=rCXeAssQ3gIrduuMzvKPD-ikt6rXejVL9h5XtDRyIQg,498
|
|
364
364
|
wafer_core/rollouts/_logging/color_formatter.py,sha256=x3qRKwHsUCFkgcIl8x_Ajjw82X2EedbTe14sCxMU4Kc,2267
|
|
365
365
|
wafer_core/rollouts/_logging/json_formatter.py,sha256=jJIa2IZCsu2C_Y1HXQi7hbI33x6L6shN_dqu-hmhxp4,2380
|
|
@@ -586,11 +586,10 @@ wafer_core/sessions/hooks.py,sha256=A-txm6ufnRGQCdtP3vwh7oEOdlLN9Tv0XsjORMihuAI,
|
|
|
586
586
|
wafer_core/targets/__init__.py,sha256=sHndC7AAOaHXlrmDXFLB53a5Y8DBjuyqS6nwsO2nj-Y,1728
|
|
587
587
|
wafer_core/targets/digitalocean.py,sha256=cvoYpYjtSyy5t2lQAPi7ERruuuibronah_ivOiduAHQ,16550
|
|
588
588
|
wafer_core/targets/runpod.py,sha256=LrVmNvA6qjzL5nbGSWvtw7CHrK6bDu7_o3vKIek00Tc,20286
|
|
589
|
-
wafer_core/tools/__init__.py,sha256=
|
|
589
|
+
wafer_core/tools/__init__.py,sha256=wBQD45GdSfkxcT6NHzIv0IMeXCc0enwwkpm3T_9j1X8,3341
|
|
590
590
|
wafer_core/tools/bash_tool.py,sha256=daoKOVGSgL0x9X_3l8Apd6-wFH4VMXMGJwVemw2FIfc,16828
|
|
591
591
|
wafer_core/tools/glob_tool.py,sha256=9X5PdOjQJj7kiVNqqCZC0-1LmnE6wHx3Zc9zfMjtXdc,3533
|
|
592
592
|
wafer_core/tools/grep_tool.py,sha256=cStyDz-J47oDLLZCL83yOvYo8Ijv4qu3D372JKT_ptM,4580
|
|
593
|
-
wafer_core/tools/search_docs_tool.py,sha256=WY4hY83sseX8Fpxvw6DZxiG-F95F2t3-4PyfMD1Lpkg,6809
|
|
594
593
|
wafer_core/tools/skill_tool.py,sha256=JXsT5hBTUH5U4tmzHEywU7eHHt5xCEF79tL2tsuk4-c,2067
|
|
595
594
|
wafer_core/tools/wafer_tool.py,sha256=-dgPTHbWXq3I3wFj0mP7-lj5iZqGRoFvFf9IEEo3plQ,6345
|
|
596
595
|
wafer_core/tools/write_kernel_tool.py,sha256=dJjhr-WBhVNe06hcJQVmBZTbS8mid64KF1MwlE2s2R4,21547
|
|
@@ -674,6 +673,6 @@ wafer_core/utils/modal_execution/modal_app.py,sha256=VfS2cX8gHtnlPXemmMcEwDPeQdh
|
|
|
674
673
|
wafer_core/utils/modal_execution/modal_config.py,sha256=7cGX9TGqilQ3qxI3OFGXV5orjtyRU-PEDOJ4vP2oxno,4421
|
|
675
674
|
wafer_core/utils/modal_execution/modal_execution.py,sha256=gChjnV6jqA3A7IRP3DfvV5cSfm_MN0X4f7JZufXgdZE,24594
|
|
676
675
|
wafer_core/utils/modal_execution/test_modal.py,sha256=_jqou_hrLs1Daf1590Pnb0a_lXMMa2rczAPpW9HpoNQ,8153
|
|
677
|
-
wafer_core-0.1.
|
|
678
|
-
wafer_core-0.1.
|
|
679
|
-
wafer_core-0.1.
|
|
676
|
+
wafer_core-0.1.25.dist-info/METADATA,sha256=hNv2xTrSbhdaA1G8mBmLxe1HbYRE0NLX3C6w89sht3k,1420
|
|
677
|
+
wafer_core-0.1.25.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
678
|
+
wafer_core-0.1.25.dist-info/RECORD,,
|
|
@@ -1,196 +0,0 @@
|
|
|
1
|
-
"""Search documentation tool for GPU programming corpora.
|
|
2
|
-
|
|
3
|
-
Provides semantic and keyword search over documentation for CuTeDSL, CUDA, etc.
|
|
4
|
-
|
|
5
|
-
Corpora are downloaded via `wafer corpus download <name>` and stored in ~/.cache/wafer/corpora/.
|
|
6
|
-
"""
|
|
7
|
-
|
|
8
|
-
import re
|
|
9
|
-
from pathlib import Path
|
|
10
|
-
|
|
11
|
-
from wafer_core.rollouts.dtypes import Tool, ToolCall, ToolFunction, ToolFunctionParameter, ToolResult
|
|
12
|
-
|
|
13
|
-
# Cache directory where wafer corpus download stores files
|
|
14
|
-
CACHE_DIR = Path.home() / ".cache" / "wafer" / "corpora"
|
|
15
|
-
|
|
16
|
-
# Available corpora (names match wafer corpus download)
|
|
17
|
-
AVAILABLE_CORPORA = ["cutlass", "cutedsl", "cuda", "hip", "amd"]
|
|
18
|
-
|
|
19
|
-
SEARCH_DOCS_TOOL = Tool(
|
|
20
|
-
type="function",
|
|
21
|
-
function=ToolFunction(
|
|
22
|
-
name="search_docs",
|
|
23
|
-
description="""Search GPU programming documentation for relevant information.
|
|
24
|
-
|
|
25
|
-
Use this tool to find documentation about:
|
|
26
|
-
- CUTLASS C++ (cute:: namespace, gemm tutorials, tensor cores, TMA, Blackwell)
|
|
27
|
-
- CuTeDSL Python API (@cute.kernel, @cute.jit, cute.arch functions)
|
|
28
|
-
- CUDA programming concepts
|
|
29
|
-
- GPU kernel optimization techniques
|
|
30
|
-
- Code examples and patterns
|
|
31
|
-
|
|
32
|
-
Available corpora:
|
|
33
|
-
- 'cutlass' - NVIDIA CUTLASS C++ docs + GitHub examples (gemm, hopper, blackwell)
|
|
34
|
-
- 'cutedsl' - CuTeDSL Python documentation
|
|
35
|
-
- 'cuda' - General CUDA programming docs
|
|
36
|
-
- 'hip' - AMD HIP programming docs
|
|
37
|
-
- 'amd' - AMD GPU kernel development (rocWMMA, CK, etc.)
|
|
38
|
-
|
|
39
|
-
Note: Corpora must be downloaded first with `wafer corpus download <name>`.
|
|
40
|
-
Returns relevant documentation snippets with file paths.""",
|
|
41
|
-
parameters=ToolFunctionParameter(
|
|
42
|
-
type="object",
|
|
43
|
-
properties={
|
|
44
|
-
"query": {
|
|
45
|
-
"type": "string",
|
|
46
|
-
"description": "Search query - describe what you're looking for",
|
|
47
|
-
},
|
|
48
|
-
"corpus": {
|
|
49
|
-
"type": "string",
|
|
50
|
-
"description": "Which docs to search: 'cutlass', 'cutedsl', 'cuda', 'hip', 'amd' (default: cutlass)",
|
|
51
|
-
},
|
|
52
|
-
"max_results": {
|
|
53
|
-
"type": "integer",
|
|
54
|
-
"description": "Maximum number of results to return (default: 5)",
|
|
55
|
-
},
|
|
56
|
-
},
|
|
57
|
-
),
|
|
58
|
-
required=["query"],
|
|
59
|
-
)
|
|
60
|
-
)
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
def _get_corpus_path(corpus_name: str) -> Path | None:
|
|
64
|
-
"""Get the path to a corpus in the cache directory.
|
|
65
|
-
|
|
66
|
-
Corpora are stored at ~/.cache/wafer/corpora/<corpus_name>/
|
|
67
|
-
"""
|
|
68
|
-
if corpus_name not in AVAILABLE_CORPORA:
|
|
69
|
-
return None
|
|
70
|
-
|
|
71
|
-
corpus_path = CACHE_DIR / corpus_name
|
|
72
|
-
if corpus_path.exists():
|
|
73
|
-
return corpus_path
|
|
74
|
-
|
|
75
|
-
return None
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
def _search_files(corpus_path: Path, query: str, max_results: int = 5) -> list[dict]:
|
|
79
|
-
"""Simple keyword search through documentation files."""
|
|
80
|
-
results = []
|
|
81
|
-
query_terms = query.lower().split()
|
|
82
|
-
|
|
83
|
-
# Search .md, .py, .cu, .hpp, and .h files (for CUTLASS examples)
|
|
84
|
-
for pattern in ["**/*.md", "**/*.py", "**/*.cu", "**/*.hpp", "**/*.h", "**/*.cuh"]:
|
|
85
|
-
for file_path in corpus_path.glob(pattern):
|
|
86
|
-
if file_path.is_file():
|
|
87
|
-
try:
|
|
88
|
-
content = file_path.read_text(encoding="utf-8", errors="ignore")
|
|
89
|
-
content_lower = content.lower()
|
|
90
|
-
|
|
91
|
-
# Score based on term matches
|
|
92
|
-
score = sum(content_lower.count(term) for term in query_terms)
|
|
93
|
-
|
|
94
|
-
if score > 0:
|
|
95
|
-
# Extract relevant snippets
|
|
96
|
-
snippets = _extract_snippets(content, query_terms)
|
|
97
|
-
results.append({
|
|
98
|
-
"file": str(file_path), # Return absolute path so read tool can access it
|
|
99
|
-
"score": score,
|
|
100
|
-
"snippets": snippets[:3], # Top 3 snippets
|
|
101
|
-
})
|
|
102
|
-
except Exception:
|
|
103
|
-
continue
|
|
104
|
-
|
|
105
|
-
# Sort by score and return top results
|
|
106
|
-
results.sort(key=lambda x: x["score"], reverse=True)
|
|
107
|
-
return results[:max_results]
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
def _extract_snippets(content: str, terms: list[str], context_lines: int = 5) -> list[str]:
|
|
111
|
-
"""Extract snippets containing search terms."""
|
|
112
|
-
snippets = []
|
|
113
|
-
lines = content.split("\n")
|
|
114
|
-
|
|
115
|
-
for i, line in enumerate(lines):
|
|
116
|
-
line_lower = line.lower()
|
|
117
|
-
if any(term in line_lower for term in terms):
|
|
118
|
-
# Get context around the match
|
|
119
|
-
start = max(0, i - context_lines)
|
|
120
|
-
end = min(len(lines), i + context_lines + 1)
|
|
121
|
-
snippet = "\n".join(lines[start:end])
|
|
122
|
-
|
|
123
|
-
# Skip very short snippets
|
|
124
|
-
if len(snippet.strip()) > 50:
|
|
125
|
-
snippets.append(snippet)
|
|
126
|
-
|
|
127
|
-
return snippets
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
async def exec_search_docs(
|
|
131
|
-
tool_call: ToolCall,
|
|
132
|
-
corpus_override: str | None = None,
|
|
133
|
-
) -> ToolResult:
|
|
134
|
-
"""Execute search_docs tool.
|
|
135
|
-
|
|
136
|
-
Args:
|
|
137
|
-
tool_call: The tool call with query and optional corpus
|
|
138
|
-
corpus_override: Override corpus path (for testing)
|
|
139
|
-
"""
|
|
140
|
-
query = tool_call.args.get("query", "")
|
|
141
|
-
corpus_name = tool_call.args.get("corpus", "cutlass")
|
|
142
|
-
max_results = tool_call.args.get("max_results", 5)
|
|
143
|
-
|
|
144
|
-
if not query:
|
|
145
|
-
return ToolResult(
|
|
146
|
-
tool_call_id=tool_call.id,
|
|
147
|
-
content="",
|
|
148
|
-
error="query parameter is required",
|
|
149
|
-
)
|
|
150
|
-
|
|
151
|
-
# Find corpus path
|
|
152
|
-
if corpus_override:
|
|
153
|
-
corpus_path = Path(corpus_override)
|
|
154
|
-
else:
|
|
155
|
-
corpus_path = _get_corpus_path(corpus_name)
|
|
156
|
-
if corpus_path is None:
|
|
157
|
-
return ToolResult(
|
|
158
|
-
tool_call_id=tool_call.id,
|
|
159
|
-
content="",
|
|
160
|
-
error=f"Unknown corpus: {corpus_name}. Available: {AVAILABLE_CORPORA}",
|
|
161
|
-
)
|
|
162
|
-
|
|
163
|
-
if not corpus_path.exists():
|
|
164
|
-
return ToolResult(
|
|
165
|
-
tool_call_id=tool_call.id,
|
|
166
|
-
content="",
|
|
167
|
-
error=f"Corpus '{corpus_name}' not downloaded. Run: wafer corpus download {corpus_name}",
|
|
168
|
-
)
|
|
169
|
-
|
|
170
|
-
# Search
|
|
171
|
-
results = _search_files(corpus_path, query, max_results)
|
|
172
|
-
|
|
173
|
-
if not results:
|
|
174
|
-
return ToolResult(
|
|
175
|
-
tool_call_id=tool_call.id,
|
|
176
|
-
content=f"No results found for query: {query}",
|
|
177
|
-
error=None,
|
|
178
|
-
)
|
|
179
|
-
|
|
180
|
-
# Format output
|
|
181
|
-
output_parts = [f"Found {len(results)} results for: {query}\n"]
|
|
182
|
-
|
|
183
|
-
for i, result in enumerate(results, 1):
|
|
184
|
-
output_parts.append(f"\n{'='*60}")
|
|
185
|
-
output_parts.append(f"[{i}] {result['file']} (score: {result['score']})")
|
|
186
|
-
output_parts.append("=" * 60)
|
|
187
|
-
|
|
188
|
-
for snippet in result["snippets"]:
|
|
189
|
-
output_parts.append(snippet)
|
|
190
|
-
output_parts.append("-" * 40)
|
|
191
|
-
|
|
192
|
-
return ToolResult(
|
|
193
|
-
tool_call_id=tool_call.id,
|
|
194
|
-
content="\n".join(output_parts),
|
|
195
|
-
error=None,
|
|
196
|
-
)
|
|
File without changes
|