Spaces:
Sleeping
Sleeping
Commit ·
95707b2
1
Parent(s): a785d13
fix /tasks endpoint format for validator
Browse files- server.log +2 -0
- sql_env/__pycache__/__init__.cpython-314.pyc +0 -0
- sql_env/__pycache__/env.cpython-314.pyc +0 -0
- sql_env/__pycache__/grader.cpython-314.pyc +0 -0
- sql_env/__pycache__/models.cpython-314.pyc +0 -0
- sql_env/__pycache__/server.cpython-314.pyc +0 -0
- sql_env/env.py +2 -2
- sql_env/grader.py +31 -13
- sql_env/models.py +6 -7
- sql_env/server.py +14 -4
- sql_env/tasks/__pycache__/__init__.cpython-314.pyc +0 -0
- sql_env/tasks/__pycache__/easy.cpython-314.pyc +0 -0
- sql_env/tasks/__pycache__/hard.cpython-314.pyc +0 -0
- sql_env/tasks/__pycache__/medium.cpython-314.pyc +0 -0
- sql_env/tasks/easy.py +7 -1
- sql_env/tasks/hard.py +5 -1
- sql_env/tasks/medium.py +7 -1
server.log
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
nohup: ignoring input
|
| 2 |
+
ERROR: Error loading ASGI app. Could not import module "app".
|
sql_env/__pycache__/__init__.cpython-314.pyc
ADDED
|
Binary file (494 Bytes). View file
|
|
|
sql_env/__pycache__/env.cpython-314.pyc
ADDED
|
Binary file (6.89 kB). View file
|
|
|
sql_env/__pycache__/grader.cpython-314.pyc
ADDED
|
Binary file (6.66 kB). View file
|
|
|
sql_env/__pycache__/models.cpython-314.pyc
ADDED
|
Binary file (3.68 kB). View file
|
|
|
sql_env/__pycache__/server.cpython-314.pyc
ADDED
|
Binary file (6.72 kB). View file
|
|
|
sql_env/env.py
CHANGED
|
@@ -69,7 +69,7 @@ class SQLCorrectionEnv:
|
|
| 69 |
if abs(reward - self._last_reward) < 0.01 and self._step_count > 1:
|
| 70 |
self._stagnation_count += 1
|
| 71 |
if self._stagnation_count >= 2:
|
| 72 |
-
reward = max(0.
|
| 73 |
else:
|
| 74 |
self._stagnation_count = 0
|
| 75 |
|
|
@@ -81,7 +81,7 @@ class SQLCorrectionEnv:
|
|
| 81 |
self._previous_attempt = action.corrected_query
|
| 82 |
|
| 83 |
# episode ends on perfect score or max steps reached
|
| 84 |
-
done = reward_model.value =
|
| 85 |
self._done = done
|
| 86 |
|
| 87 |
obs = self._make_observation()
|
|
|
|
| 69 |
if abs(reward - self._last_reward) < 0.01 and self._step_count > 1:
|
| 70 |
self._stagnation_count += 1
|
| 71 |
if self._stagnation_count >= 2:
|
| 72 |
+
reward = max(0.001, reward - 0.1) # stagnation penalty
|
| 73 |
else:
|
| 74 |
self._stagnation_count = 0
|
| 75 |
|
|
|
|
| 81 |
self._previous_attempt = action.corrected_query
|
| 82 |
|
| 83 |
# episode ends on perfect score or max steps reached
|
| 84 |
+
done = reward_model.value >= 0.99 or self._step_count >= self._task.max_steps
|
| 85 |
self._done = done
|
| 86 |
|
| 87 |
obs = self._make_observation()
|
sql_env/grader.py
CHANGED
|
@@ -2,6 +2,11 @@ import re
|
|
| 2 |
from sql_env.models import SQLAction, SQLTask, SQLReward
|
| 3 |
|
| 4 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5 |
def _normalize(query: str) -> str:
|
| 6 |
"""Uppercase, collapse whitespace, strip trailing semicolons."""
|
| 7 |
q = query.strip().upper()
|
|
@@ -11,7 +16,9 @@ def _normalize(query: str) -> str:
|
|
| 11 |
|
| 12 |
|
| 13 |
def _tokenize(query: str) -> set:
|
| 14 |
-
|
|
|
|
|
|
|
| 15 |
|
| 16 |
|
| 17 |
def _sql_keywords_present(query: str) -> set:
|
|
@@ -33,26 +40,29 @@ def _sql_keywords_present(query: str) -> set:
|
|
| 33 |
def grade(action: SQLAction, task: SQLTask) -> SQLReward:
|
| 34 |
"""
|
| 35 |
4-level grader with partial progress signals.
|
| 36 |
-
|
| 37 |
0.99 — exact normalized match
|
| 38 |
-
0.7
|
| 39 |
-
0.4
|
| 40 |
-
0.2
|
| 41 |
0.01 — completely wrong
|
|
|
|
| 42 |
"""
|
| 43 |
agent = _normalize(action.corrected_query)
|
| 44 |
correct = _normalize(task.canonical_answer)
|
| 45 |
|
| 46 |
# ── Level 1: Exact match ─────────────────────────────────
|
| 47 |
if agent == correct:
|
| 48 |
-
return SQLReward(
|
|
|
|
|
|
|
|
|
|
| 49 |
|
| 50 |
# ── Level 2: Same token set (right words, minor ordering) ─
|
| 51 |
agent_tokens = _tokenize(action.corrected_query)
|
| 52 |
correct_tokens = _tokenize(task.canonical_answer)
|
| 53 |
if agent_tokens == correct_tokens:
|
| 54 |
return SQLReward(
|
| 55 |
-
value=0.7,
|
| 56 |
reason="All correct tokens present but structure differs slightly."
|
| 57 |
)
|
| 58 |
|
|
@@ -60,34 +70,42 @@ def grade(action: SQLAction, task: SQLTask) -> SQLReward:
|
|
| 60 |
correct_kws = _sql_keywords_present(task.canonical_answer)
|
| 61 |
agent_kws = _sql_keywords_present(action.corrected_query)
|
| 62 |
kw_overlap = len(correct_kws & agent_kws) / max(len(correct_kws), 1)
|
| 63 |
-
|
| 64 |
token_overlap = len(agent_tokens & correct_tokens) / max(len(correct_tokens), 1)
|
| 65 |
|
| 66 |
if kw_overlap >= 0.85 and token_overlap >= 0.75:
|
| 67 |
return SQLReward(
|
| 68 |
-
value=0.4,
|
| 69 |
reason=f"Most keywords correct ({kw_overlap:.0%} keyword match, {token_overlap:.0%} token match)."
|
| 70 |
)
|
| 71 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 72 |
# ── Level 4: Basic structure present ─────────────────────
|
| 73 |
if 'SELECT' in agent and 'FROM' in agent:
|
| 74 |
return SQLReward(
|
| 75 |
-
value=0.2,
|
| 76 |
reason="Basic SELECT/FROM structure present but significant errors remain."
|
| 77 |
)
|
| 78 |
|
| 79 |
# ── Level 0: No recognizable SQL ─────────────────────────
|
| 80 |
-
return SQLReward(value=0.01, reason="Response is not valid SQL.")
|
| 81 |
|
| 82 |
|
| 83 |
def generate_feedback(action: SQLAction, task: SQLTask, reward: SQLReward) -> str:
|
| 84 |
"""Human-readable feedback shown in next observation."""
|
| 85 |
-
if reward.value =
|
| 86 |
return "Correct! Query matches perfectly."
|
| 87 |
if reward.value >= 0.7:
|
| 88 |
return "Very close — check spacing or minor clause differences."
|
| 89 |
if reward.value >= 0.4:
|
| 90 |
return "Good progress — most keywords are right, but check for typos in keywords or column names."
|
|
|
|
|
|
|
| 91 |
if reward.value >= 0.2:
|
| 92 |
return "Basic structure is there — look carefully at every SQL keyword for typos."
|
| 93 |
-
return "The response doesn't look like valid SQL. Start with SELECT ... FROM ..."
|
|
|
|
| 2 |
from sql_env.models import SQLAction, SQLTask, SQLReward
|
| 3 |
|
| 4 |
|
| 5 |
+
def _clamp(value: float) -> float:
|
| 6 |
+
"""Ensure score is strictly between 0 and 1 (gt=0.0, lt=1.0)."""
|
| 7 |
+
return max(0.001, min(0.999, value))
|
| 8 |
+
|
| 9 |
+
|
| 10 |
def _normalize(query: str) -> str:
|
| 11 |
"""Uppercase, collapse whitespace, strip trailing semicolons."""
|
| 12 |
q = query.strip().upper()
|
|
|
|
| 16 |
|
| 17 |
|
| 18 |
def _tokenize(query: str) -> set:
|
| 19 |
+
normed = _normalize(query)
|
| 20 |
+
normed = re.sub(r"'[^']*'", '__STR__', normed) # normalize string literals
|
| 21 |
+
return set(re.findall(r"[A-Z0-9_'*.=><]+", normed))
|
| 22 |
|
| 23 |
|
| 24 |
def _sql_keywords_present(query: str) -> set:
|
|
|
|
| 40 |
def grade(action: SQLAction, task: SQLTask) -> SQLReward:
|
| 41 |
"""
|
| 42 |
4-level grader with partial progress signals.
|
|
|
|
| 43 |
0.99 — exact normalized match
|
| 44 |
+
0.7 — same tokens, minor whitespace/alias differences
|
| 45 |
+
0.4 — key SQL keywords all present and correct table/column names
|
| 46 |
+
0.2 — basic SELECT/FROM structure present
|
| 47 |
0.01 — completely wrong
|
| 48 |
+
All scores are clamped to be strictly between 0.0 and 1.0.
|
| 49 |
"""
|
| 50 |
agent = _normalize(action.corrected_query)
|
| 51 |
correct = _normalize(task.canonical_answer)
|
| 52 |
|
| 53 |
# ── Level 1: Exact match ─────────────────────────────────
|
| 54 |
if agent == correct:
|
| 55 |
+
return SQLReward(
|
| 56 |
+
value=_clamp(0.99),
|
| 57 |
+
reason="Exact match — perfect correction."
|
| 58 |
+
)
|
| 59 |
|
| 60 |
# ── Level 2: Same token set (right words, minor ordering) ─
|
| 61 |
agent_tokens = _tokenize(action.corrected_query)
|
| 62 |
correct_tokens = _tokenize(task.canonical_answer)
|
| 63 |
if agent_tokens == correct_tokens:
|
| 64 |
return SQLReward(
|
| 65 |
+
value=_clamp(0.7),
|
| 66 |
reason="All correct tokens present but structure differs slightly."
|
| 67 |
)
|
| 68 |
|
|
|
|
| 70 |
correct_kws = _sql_keywords_present(task.canonical_answer)
|
| 71 |
agent_kws = _sql_keywords_present(action.corrected_query)
|
| 72 |
kw_overlap = len(correct_kws & agent_kws) / max(len(correct_kws), 1)
|
|
|
|
| 73 |
token_overlap = len(agent_tokens & correct_tokens) / max(len(correct_tokens), 1)
|
| 74 |
|
| 75 |
if kw_overlap >= 0.85 and token_overlap >= 0.75:
|
| 76 |
return SQLReward(
|
| 77 |
+
value=_clamp(0.4),
|
| 78 |
reason=f"Most keywords correct ({kw_overlap:.0%} keyword match, {token_overlap:.0%} token match)."
|
| 79 |
)
|
| 80 |
|
| 81 |
+
# ── Level 3.5: Partial keyword and structure match ────────
|
| 82 |
+
if kw_overlap >= 0.7 and token_overlap >= 0.55:
|
| 83 |
+
return SQLReward(
|
| 84 |
+
value=_clamp(0.3),
|
| 85 |
+
reason=f"Partial keyword and structure match ({kw_overlap:.0%} keyword match, {token_overlap:.0%} token match)."
|
| 86 |
+
)
|
| 87 |
+
|
| 88 |
# ── Level 4: Basic structure present ─────────────────────
|
| 89 |
if 'SELECT' in agent and 'FROM' in agent:
|
| 90 |
return SQLReward(
|
| 91 |
+
value=_clamp(0.2),
|
| 92 |
reason="Basic SELECT/FROM structure present but significant errors remain."
|
| 93 |
)
|
| 94 |
|
| 95 |
# ── Level 0: No recognizable SQL ─────────────────────────
|
| 96 |
+
return SQLReward(value=_clamp(0.01), reason="Response is not valid SQL.")
|
| 97 |
|
| 98 |
|
| 99 |
def generate_feedback(action: SQLAction, task: SQLTask, reward: SQLReward) -> str:
|
| 100 |
"""Human-readable feedback shown in next observation."""
|
| 101 |
+
if reward.value >= 0.99:
|
| 102 |
return "Correct! Query matches perfectly."
|
| 103 |
if reward.value >= 0.7:
|
| 104 |
return "Very close — check spacing or minor clause differences."
|
| 105 |
if reward.value >= 0.4:
|
| 106 |
return "Good progress — most keywords are right, but check for typos in keywords or column names."
|
| 107 |
+
if reward.value >= 0.3:
|
| 108 |
+
return "Partial match — right direction but several keywords or columns are off."
|
| 109 |
if reward.value >= 0.2:
|
| 110 |
return "Basic structure is there — look carefully at every SQL keyword for typos."
|
| 111 |
+
return "The response doesn't look like valid SQL. Start with SELECT ... FROM ..."
|
sql_env/models.py
CHANGED
|
@@ -1,6 +1,5 @@
|
|
| 1 |
from pydantic import BaseModel, Field
|
| 2 |
-
from typing import Optional, Any, Dict
|
| 3 |
-
|
| 4 |
|
| 5 |
class SQLObservation(BaseModel):
|
| 6 |
task_id: str
|
|
@@ -11,16 +10,13 @@ class SQLObservation(BaseModel):
|
|
| 11 |
previous_attempt: Optional[str] = None
|
| 12 |
feedback: Optional[str] = None
|
| 13 |
|
| 14 |
-
|
| 15 |
class SQLAction(BaseModel):
|
| 16 |
corrected_query: str
|
| 17 |
|
| 18 |
-
|
| 19 |
class SQLReward(BaseModel):
|
| 20 |
-
value: float = Field(
|
| 21 |
reason: str
|
| 22 |
|
| 23 |
-
|
| 24 |
class SQLTask(BaseModel):
|
| 25 |
task_id: str
|
| 26 |
difficulty: str
|
|
@@ -29,10 +25,13 @@ class SQLTask(BaseModel):
|
|
| 29 |
schema_context: Optional[str] = None
|
| 30 |
error_hint: Optional[str] = None
|
| 31 |
max_steps: int = 5
|
|
|
|
| 32 |
|
|
|
|
|
|
|
| 33 |
|
| 34 |
class StepResult(BaseModel):
|
| 35 |
observation: SQLObservation
|
| 36 |
reward: float
|
| 37 |
done: bool
|
| 38 |
-
info: Dict[str, Any] = Field(default_factory=dict)
|
|
|
|
| 1 |
from pydantic import BaseModel, Field
|
| 2 |
+
from typing import Optional, Any, Dict, Callable
|
|
|
|
| 3 |
|
| 4 |
class SQLObservation(BaseModel):
|
| 5 |
task_id: str
|
|
|
|
| 10 |
previous_attempt: Optional[str] = None
|
| 11 |
feedback: Optional[str] = None
|
| 12 |
|
|
|
|
| 13 |
class SQLAction(BaseModel):
|
| 14 |
corrected_query: str
|
| 15 |
|
|
|
|
| 16 |
class SQLReward(BaseModel):
|
| 17 |
+
value: float = Field(gt=0.0, lt=1.0) # strictly between, not ge/le
|
| 18 |
reason: str
|
| 19 |
|
|
|
|
| 20 |
class SQLTask(BaseModel):
|
| 21 |
task_id: str
|
| 22 |
difficulty: str
|
|
|
|
| 25 |
schema_context: Optional[str] = None
|
| 26 |
error_hint: Optional[str] = None
|
| 27 |
max_steps: int = 5
|
| 28 |
+
grader: Optional[Callable] = None # ← add this
|
| 29 |
|
| 30 |
+
class Config:
|
| 31 |
+
arbitrary_types_allowed = True # ← required for Callable in Pydantic
|
| 32 |
|
| 33 |
class StepResult(BaseModel):
|
| 34 |
observation: SQLObservation
|
| 35 |
reward: float
|
| 36 |
done: bool
|
| 37 |
+
info: Dict[str, Any] = Field(default_factory=dict)
|
sql_env/server.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
| 1 |
"""
|
| 2 |
FastAPI HTTP wrapper for SQLCorrectionEnv.
|
| 3 |
|
| 4 |
-
Exposes the OpenEnv-required endpoints: /reset, /step, /state.
|
| 5 |
"""
|
| 6 |
|
| 7 |
from contextlib import asynccontextmanager
|
|
@@ -12,6 +12,7 @@ from fastapi.middleware.cors import CORSMiddleware
|
|
| 12 |
from pydantic import BaseModel
|
| 13 |
|
| 14 |
from sql_env import SQLAction, SQLCorrectionEnv
|
|
|
|
| 15 |
|
| 16 |
|
| 17 |
class ResetRequest(BaseModel):
|
|
@@ -96,21 +97,30 @@ async def health():
|
|
| 96 |
return {"status": "ok", "service": "sql-correction-env"}
|
| 97 |
|
| 98 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 99 |
@app.get("/")
|
| 100 |
async def root():
|
| 101 |
return {
|
| 102 |
"name": "SQL Correction RL Environment",
|
| 103 |
"version": "1.0.0",
|
| 104 |
-
"endpoints": ["/reset", "/step", "/state", "/health"],
|
| 105 |
"tasks": ["easy", "medium", "hard"],
|
| 106 |
}
|
| 107 |
|
| 108 |
|
| 109 |
def main():
|
| 110 |
import uvicorn
|
| 111 |
-
|
| 112 |
uvicorn.run(app, host="0.0.0.0", port=7860)
|
| 113 |
|
| 114 |
|
| 115 |
if __name__ == "__main__":
|
| 116 |
-
main()
|
|
|
|
| 1 |
"""
|
| 2 |
FastAPI HTTP wrapper for SQLCorrectionEnv.
|
| 3 |
|
| 4 |
+
Exposes the OpenEnv-required endpoints: /reset, /step, /state + /tasks for validator.
|
| 5 |
"""
|
| 6 |
|
| 7 |
from contextlib import asynccontextmanager
|
|
|
|
| 12 |
from pydantic import BaseModel
|
| 13 |
|
| 14 |
from sql_env import SQLAction, SQLCorrectionEnv
|
| 15 |
+
from sql_env.tasks import ALL_TASKS
|
| 16 |
|
| 17 |
|
| 18 |
class ResetRequest(BaseModel):
|
|
|
|
| 97 |
return {"status": "ok", "service": "sql-correction-env"}
|
| 98 |
|
| 99 |
|
| 100 |
+
@app.get("/tasks")
|
| 101 |
+
async def list_tasks():
|
| 102 |
+
"""Return graded tasks by difficulty (RL validator format)."""
|
| 103 |
+
graded_tasks = {
|
| 104 |
+
diff: [task.__dict__ for task in tasks if task.grader is not None]
|
| 105 |
+
for diff, tasks in ALL_TASKS.items()
|
| 106 |
+
}
|
| 107 |
+
return graded_tasks # {"easy": [tasks], "medium": [tasks], "hard": [tasks]}
|
| 108 |
+
|
| 109 |
+
|
| 110 |
@app.get("/")
|
| 111 |
async def root():
|
| 112 |
return {
|
| 113 |
"name": "SQL Correction RL Environment",
|
| 114 |
"version": "1.0.0",
|
| 115 |
+
"endpoints": ["/reset", "/step", "/state", "/health", "/tasks"],
|
| 116 |
"tasks": ["easy", "medium", "hard"],
|
| 117 |
}
|
| 118 |
|
| 119 |
|
| 120 |
def main():
|
| 121 |
import uvicorn
|
|
|
|
| 122 |
uvicorn.run(app, host="0.0.0.0", port=7860)
|
| 123 |
|
| 124 |
|
| 125 |
if __name__ == "__main__":
|
| 126 |
+
main()
|
sql_env/tasks/__pycache__/__init__.cpython-314.pyc
ADDED
|
Binary file (436 Bytes). View file
|
|
|
sql_env/tasks/__pycache__/easy.cpython-314.pyc
ADDED
|
Binary file (1.28 kB). View file
|
|
|
sql_env/tasks/__pycache__/hard.cpython-314.pyc
ADDED
|
Binary file (2.78 kB). View file
|
|
|
sql_env/tasks/__pycache__/medium.cpython-314.pyc
ADDED
|
Binary file (1.58 kB). View file
|
|
|
sql_env/tasks/easy.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
| 1 |
from sql_env.models import SQLTask
|
|
|
|
| 2 |
|
| 3 |
EASY_TASKS = [
|
| 4 |
SQLTask(
|
|
@@ -7,6 +8,7 @@ EASY_TASKS = [
|
|
| 7 |
broken_query="SELECT * FORM users WHERE id = 1",
|
| 8 |
canonical_answer="SELECT * FROM users WHERE id = 1",
|
| 9 |
error_hint="There is a typo in a SQL keyword near the table name.",
|
|
|
|
| 10 |
),
|
| 11 |
SQLTask(
|
| 12 |
task_id="easy_002",
|
|
@@ -14,6 +16,7 @@ EASY_TASKS = [
|
|
| 14 |
broken_query="SELECT name, age FORM employees WHERE department = 'HR'",
|
| 15 |
canonical_answer="SELECT name, age FROM employees WHERE department = 'HR'",
|
| 16 |
error_hint="There is a typo in a SQL keyword near the table name.",
|
|
|
|
| 17 |
),
|
| 18 |
SQLTask(
|
| 19 |
task_id="easy_003",
|
|
@@ -21,6 +24,7 @@ EASY_TASKS = [
|
|
| 21 |
broken_query="SELECT * FROM products WEHRE price > 100",
|
| 22 |
canonical_answer="SELECT * FROM products WHERE price > 100",
|
| 23 |
error_hint="There is a typo in the filtering keyword.",
|
|
|
|
| 24 |
),
|
| 25 |
SQLTask(
|
| 26 |
task_id="easy_004",
|
|
@@ -28,6 +32,7 @@ EASY_TASKS = [
|
|
| 28 |
broken_query="SELCT id, name FROM customers",
|
| 29 |
canonical_answer="SELECT id, name FROM customers",
|
| 30 |
error_hint="There is a typo in the first keyword of the query.",
|
|
|
|
| 31 |
),
|
| 32 |
SQLTask(
|
| 33 |
task_id="easy_005",
|
|
@@ -35,5 +40,6 @@ EASY_TASKS = [
|
|
| 35 |
broken_query="SELECT COUNT(*) FORM orders WHERE status = 'pending'",
|
| 36 |
canonical_answer="SELECT COUNT(*) FROM orders WHERE status = 'pending'",
|
| 37 |
error_hint="There is a typo in a SQL keyword near the table name.",
|
|
|
|
| 38 |
),
|
| 39 |
-
]
|
|
|
|
| 1 |
from sql_env.models import SQLTask
|
| 2 |
+
from sql_env.grader import grade
|
| 3 |
|
| 4 |
EASY_TASKS = [
|
| 5 |
SQLTask(
|
|
|
|
| 8 |
broken_query="SELECT * FORM users WHERE id = 1",
|
| 9 |
canonical_answer="SELECT * FROM users WHERE id = 1",
|
| 10 |
error_hint="There is a typo in a SQL keyword near the table name.",
|
| 11 |
+
grader=grade,
|
| 12 |
),
|
| 13 |
SQLTask(
|
| 14 |
task_id="easy_002",
|
|
|
|
| 16 |
broken_query="SELECT name, age FORM employees WHERE department = 'HR'",
|
| 17 |
canonical_answer="SELECT name, age FROM employees WHERE department = 'HR'",
|
| 18 |
error_hint="There is a typo in a SQL keyword near the table name.",
|
| 19 |
+
grader=grade,
|
| 20 |
),
|
| 21 |
SQLTask(
|
| 22 |
task_id="easy_003",
|
|
|
|
| 24 |
broken_query="SELECT * FROM products WEHRE price > 100",
|
| 25 |
canonical_answer="SELECT * FROM products WHERE price > 100",
|
| 26 |
error_hint="There is a typo in the filtering keyword.",
|
| 27 |
+
grader=grade,
|
| 28 |
),
|
| 29 |
SQLTask(
|
| 30 |
task_id="easy_004",
|
|
|
|
| 32 |
broken_query="SELCT id, name FROM customers",
|
| 33 |
canonical_answer="SELECT id, name FROM customers",
|
| 34 |
error_hint="There is a typo in the first keyword of the query.",
|
| 35 |
+
grader=grade,
|
| 36 |
),
|
| 37 |
SQLTask(
|
| 38 |
task_id="easy_005",
|
|
|
|
| 40 |
broken_query="SELECT COUNT(*) FORM orders WHERE status = 'pending'",
|
| 41 |
canonical_answer="SELECT COUNT(*) FROM orders WHERE status = 'pending'",
|
| 42 |
error_hint="There is a typo in a SQL keyword near the table name.",
|
| 43 |
+
grader=grade,
|
| 44 |
),
|
| 45 |
+
]
|
sql_env/tasks/hard.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
| 1 |
from sql_env.models import SQLTask
|
|
|
|
| 2 |
|
| 3 |
HARD_TASKS = [
|
| 4 |
SQLTask(
|
|
@@ -13,6 +14,7 @@ HARD_TASKS = [
|
|
| 13 |
),
|
| 14 |
error_hint=None,
|
| 15 |
max_steps=4,
|
|
|
|
| 16 |
),
|
| 17 |
SQLTask(
|
| 18 |
task_id="hard_002",
|
|
@@ -27,6 +29,7 @@ HARD_TASKS = [
|
|
| 27 |
),
|
| 28 |
error_hint=None,
|
| 29 |
max_steps=4,
|
|
|
|
| 30 |
),
|
| 31 |
SQLTask(
|
| 32 |
task_id="hard_003",
|
|
@@ -38,5 +41,6 @@ HARD_TASKS = [
|
|
| 38 |
),
|
| 39 |
error_hint=None,
|
| 40 |
max_steps=4,
|
|
|
|
| 41 |
),
|
| 42 |
-
]
|
|
|
|
| 1 |
from sql_env.models import SQLTask
|
| 2 |
+
from sql_env.grader import grade
|
| 3 |
|
| 4 |
HARD_TASKS = [
|
| 5 |
SQLTask(
|
|
|
|
| 14 |
),
|
| 15 |
error_hint=None,
|
| 16 |
max_steps=4,
|
| 17 |
+
grader=grade,
|
| 18 |
),
|
| 19 |
SQLTask(
|
| 20 |
task_id="hard_002",
|
|
|
|
| 29 |
),
|
| 30 |
error_hint=None,
|
| 31 |
max_steps=4,
|
| 32 |
+
grader=grade,
|
| 33 |
),
|
| 34 |
SQLTask(
|
| 35 |
task_id="hard_003",
|
|
|
|
| 41 |
),
|
| 42 |
error_hint=None,
|
| 43 |
max_steps=4,
|
| 44 |
+
grader=grade,
|
| 45 |
),
|
| 46 |
+
]
|
sql_env/tasks/medium.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
| 1 |
from sql_env.models import SQLTask
|
|
|
|
| 2 |
|
| 3 |
MEDIUM_TASKS = [
|
| 4 |
SQLTask(
|
|
@@ -7,6 +8,7 @@ MEDIUM_TASKS = [
|
|
| 7 |
broken_query="SELECT name, SUM(salary) FORM employees GRUP BY department",
|
| 8 |
canonical_answer="SELECT name, SUM(salary) FROM employees GROUP BY department",
|
| 9 |
error_hint=None,
|
|
|
|
| 10 |
),
|
| 11 |
SQLTask(
|
| 12 |
task_id="medium_002",
|
|
@@ -14,6 +16,7 @@ MEDIUM_TASKS = [
|
|
| 14 |
broken_query="SELECT * FROM orders WHER total > 500 AND status = 'active' ORDR BY total DESC",
|
| 15 |
canonical_answer="SELECT * FROM orders WHERE total > 500 AND status = 'active' ORDER BY total DESC",
|
| 16 |
error_hint=None,
|
|
|
|
| 17 |
),
|
| 18 |
SQLTask(
|
| 19 |
task_id="medium_003",
|
|
@@ -21,6 +24,7 @@ MEDIUM_TASKS = [
|
|
| 21 |
broken_query="SELECT department, COUNT(*) AS emp_count FORM employees GROUP BY department HAVNG COUNT(*) > 5",
|
| 22 |
canonical_answer="SELECT department, COUNT(*) AS emp_count FROM employees GROUP BY department HAVING COUNT(*) > 5",
|
| 23 |
error_hint=None,
|
|
|
|
| 24 |
),
|
| 25 |
SQLTask(
|
| 26 |
task_id="medium_004",
|
|
@@ -28,6 +32,7 @@ MEDIUM_TASKS = [
|
|
| 28 |
broken_query="SELCT product_id, SUM(quantity) FROM sales WEHRE year = 2024 GROUP BY product_id",
|
| 29 |
canonical_answer="SELECT product_id, SUM(quantity) FROM sales WHERE year = 2024 GROUP BY product_id",
|
| 30 |
error_hint=None,
|
|
|
|
| 31 |
),
|
| 32 |
SQLTask(
|
| 33 |
task_id="medium_005",
|
|
@@ -35,5 +40,6 @@ MEDIUM_TASKS = [
|
|
| 35 |
broken_query="SELECT e.name, d.dept_name FORM employees e INNE JOIN departments d ON e.dept_id = d.id WHER e.salary > 50000",
|
| 36 |
canonical_answer="SELECT e.name, d.dept_name FROM employees e INNER JOIN departments d ON e.dept_id = d.id WHERE e.salary > 50000",
|
| 37 |
error_hint=None,
|
|
|
|
| 38 |
),
|
| 39 |
-
]
|
|
|
|
| 1 |
from sql_env.models import SQLTask
|
| 2 |
+
from sql_env.grader import grade
|
| 3 |
|
| 4 |
MEDIUM_TASKS = [
|
| 5 |
SQLTask(
|
|
|
|
| 8 |
broken_query="SELECT name, SUM(salary) FORM employees GRUP BY department",
|
| 9 |
canonical_answer="SELECT name, SUM(salary) FROM employees GROUP BY department",
|
| 10 |
error_hint=None,
|
| 11 |
+
grader=grade,
|
| 12 |
),
|
| 13 |
SQLTask(
|
| 14 |
task_id="medium_002",
|
|
|
|
| 16 |
broken_query="SELECT * FROM orders WHER total > 500 AND status = 'active' ORDR BY total DESC",
|
| 17 |
canonical_answer="SELECT * FROM orders WHERE total > 500 AND status = 'active' ORDER BY total DESC",
|
| 18 |
error_hint=None,
|
| 19 |
+
grader=grade,
|
| 20 |
),
|
| 21 |
SQLTask(
|
| 22 |
task_id="medium_003",
|
|
|
|
| 24 |
broken_query="SELECT department, COUNT(*) AS emp_count FORM employees GROUP BY department HAVNG COUNT(*) > 5",
|
| 25 |
canonical_answer="SELECT department, COUNT(*) AS emp_count FROM employees GROUP BY department HAVING COUNT(*) > 5",
|
| 26 |
error_hint=None,
|
| 27 |
+
grader=grade,
|
| 28 |
),
|
| 29 |
SQLTask(
|
| 30 |
task_id="medium_004",
|
|
|
|
| 32 |
broken_query="SELCT product_id, SUM(quantity) FROM sales WEHRE year = 2024 GROUP BY product_id",
|
| 33 |
canonical_answer="SELECT product_id, SUM(quantity) FROM sales WHERE year = 2024 GROUP BY product_id",
|
| 34 |
error_hint=None,
|
| 35 |
+
grader=grade,
|
| 36 |
),
|
| 37 |
SQLTask(
|
| 38 |
task_id="medium_005",
|
|
|
|
| 40 |
broken_query="SELECT e.name, d.dept_name FORM employees e INNE JOIN departments d ON e.dept_id = d.id WHER e.salary > 50000",
|
| 41 |
canonical_answer="SELECT e.name, d.dept_name FROM employees e INNER JOIN departments d ON e.dept_id = d.id WHERE e.salary > 50000",
|
| 42 |
error_hint=None,
|
| 43 |
+
grader=grade,
|
| 44 |
),
|
| 45 |
+
]
|