NeerajCodz commited on
Commit
13402be
·
1 Parent(s): dc6c23a

fix: proper rewards for all steps and clean CSV output

Browse files

- Added rewards to plugin, planner, planner_python, navigator, navigator_python steps
- Navigation step now gets 0.5 reward on success
- Extraction step calculates reward based on repo count (0.5 per repo + 1.0 bonus)
- CSV output now returns clean data without nested structure
- format_output() checks for csv_output key and returns it directly
- Total rewards now accumulate correctly across all steps

Files changed (1) hide show
  1. backend/app/api/routes/scrape.py +80 -16
backend/app/api/routes/scrape.py CHANGED
@@ -311,6 +311,11 @@ async def format_output(data: dict[str, Any], output_format: OutputFormat, _inst
311
  return json.dumps(data, indent=2, default=str)
312
 
313
  if output_format == OutputFormat.CSV:
 
 
 
 
 
314
  if (
315
  isinstance(data, dict)
316
  and isinstance(data.get("rows"), list)
@@ -827,7 +832,26 @@ async def _scrape_github_trending(
827
  )
828
 
829
  nav_obs, reward, _, _, _, nav_info = await env.step(navigate_action)
830
- total_reward += reward
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
831
 
832
  if not nav_obs.page_html:
833
  session["errors"].append("Failed to load GitHub trending page")
@@ -845,6 +869,7 @@ async def _scrape_github_trending(
845
  url=trending_url,
846
  status="running",
847
  message="Extracting trending repositories...",
 
848
  timestamp=_now_iso(),
849
  ),
850
  )
@@ -894,36 +919,69 @@ async def _scrape_github_trending(
894
  logger.warning(f"Failed to parse repo entry: {exc}")
895
  continue
896
 
897
- # Store results
 
 
 
898
  step_num += 1
899
  yield _record_step(
900
  session,
901
  ScrapeStep(
902
  step_number=step_num,
903
- action="complete",
904
  url=trending_url,
905
  status="completed",
906
  message=f"Extracted {len(trending_repos)} trending repositories",
907
- reward=total_reward + len(trending_repos) * 0.5,
908
- extracted_data={"trending_repos": trending_repos},
909
  timestamp=_now_iso(),
910
  ),
911
  )
912
 
913
- # Format as CSV
914
- if request.output_format == "csv" and trending_repos:
915
- csv_buffer = io.StringIO()
916
- writer = csv.DictWriter(csv_buffer, fieldnames=["username", "repo_name", "stars", "forks"])
917
- writer.writeheader()
918
- writer.writerows(trending_repos)
919
-
920
- session["final_output"] = csv_buffer.getvalue()
 
 
 
 
 
 
 
 
 
 
921
  session["extracted_data"][trending_url] = {
922
  "trending_repositories": trending_repos,
923
- "csv_output": csv_buffer.getvalue()
924
  }
925
-
926
- _write_session_artifact(session, "trending_repos.csv", csv_buffer.getvalue())
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
927
 
928
 
929
  async def _scrape_single_page(
@@ -1132,6 +1190,7 @@ async def scrape_stream(
1132
  message=(
1133
  f"Enabled plugins: {enabled_plugins}" if enabled_plugins else "No plugins enabled"
1134
  ),
 
1135
  extracted_data={
1136
  "requested": request.enable_plugins,
1137
  "enabled": enabled_plugins,
@@ -1158,6 +1217,7 @@ async def scrape_stream(
1158
  action="mcp_search",
1159
  status="completed",
1160
  message="Resolved non-URL assets using search/discovery plugin logic",
 
1161
  extracted_data={"discoveries": discoveries, "resolved_assets": resolved_assets},
1162
  timestamp=_now_iso(),
1163
  ),
@@ -1205,6 +1265,7 @@ async def scrape_stream(
1205
  action="planner",
1206
  status="completed",
1207
  message=f"Planner created execution plan for {len(resolved_assets)} assets",
 
1208
  extracted_data={
1209
  "assets": resolved_assets,
1210
  "instructions": request.instructions,
@@ -1254,6 +1315,7 @@ async def scrape_stream(
1254
  action="planner_python",
1255
  status="completed",
1256
  message="Planner agent executed sandbox Python code",
 
1257
  extracted_data=planner_sandbox.output,
1258
  timestamp=_now_iso(),
1259
  ),
@@ -1273,6 +1335,7 @@ async def scrape_stream(
1273
  url=url,
1274
  status="running",
1275
  message=f"Navigator selected source {idx + 1}/{len(resolved_assets)}",
 
1276
  timestamp=_now_iso(),
1277
  ),
1278
  )
@@ -1317,6 +1380,7 @@ async def scrape_stream(
1317
  url=url,
1318
  status="completed",
1319
  message="Navigator agent executed sandbox Python code",
 
1320
  extracted_data=navigator_sandbox.output,
1321
  timestamp=_now_iso(),
1322
  ),
 
311
  return json.dumps(data, indent=2, default=str)
312
 
313
  if output_format == OutputFormat.CSV:
314
+ # Check if there's a pre-formatted csv_output
315
+ if isinstance(data, dict) and "csv_output" in data:
316
+ return data["csv_output"]
317
+
318
+ # Check for rows format
319
  if (
320
  isinstance(data, dict)
321
  and isinstance(data.get("rows"), list)
 
832
  )
833
 
834
  nav_obs, reward, _, _, _, nav_info = await env.step(navigate_action)
835
+
836
+ # Calculate navigation reward (0.5 for successful navigation)
837
+ nav_reward = 0.5 if nav_obs.page_html else 0.0
838
+ total_reward += nav_reward
839
+
840
+ # Update the navigation step with actual reward
841
+ step_num += 1
842
+ yield _record_step(
843
+ session,
844
+ ScrapeStep(
845
+ step_number=step_num,
846
+ action="navigate",
847
+ url=trending_url,
848
+ status="completed" if nav_obs.page_html else "failed",
849
+ message=f"Navigated to {trending_url}" if nav_obs.page_html else "Navigation failed",
850
+ reward=nav_reward,
851
+ duration_ms=nav_info.get("step_duration_ms", 0),
852
+ timestamp=_now_iso(),
853
+ ),
854
+ )
855
 
856
  if not nav_obs.page_html:
857
  session["errors"].append("Failed to load GitHub trending page")
 
869
  url=trending_url,
870
  status="running",
871
  message="Extracting trending repositories...",
872
+ reward=0.1, # Small reward for starting extraction
873
  timestamp=_now_iso(),
874
  ),
875
  )
 
919
  logger.warning(f"Failed to parse repo entry: {exc}")
920
  continue
921
 
922
+ # Calculate extraction reward based on repo count
923
+ extraction_reward = len(trending_repos) * 0.5 + (1.0 if len(trending_repos) >= 10 else 0.5)
924
+ total_reward += extraction_reward
925
+
926
  step_num += 1
927
  yield _record_step(
928
  session,
929
  ScrapeStep(
930
  step_number=step_num,
931
+ action="extract",
932
  url=trending_url,
933
  status="completed",
934
  message=f"Extracted {len(trending_repos)} trending repositories",
935
+ reward=extraction_reward,
936
+ extracted_data={"count": len(trending_repos), "repos": trending_repos[:3]}, # Preview only
937
  timestamp=_now_iso(),
938
  ),
939
  )
940
 
941
+ # Generate clean CSV output
942
+ csv_buffer = io.StringIO()
943
+ writer = csv.DictWriter(csv_buffer, fieldnames=["username", "repo_name", "stars", "forks"])
944
+ writer.writeheader()
945
+ writer.writerows(trending_repos)
946
+ clean_csv = csv_buffer.getvalue()
947
+
948
+ # Store the clean CSV directly as extracted data for CSV output format
949
+ if request.output_format == OutputFormat.CSV:
950
+ session["extracted_data"] = {
951
+ "rows": trending_repos,
952
+ "columns": ["username", "repo_name", "stars", "forks"],
953
+ "csv_output": clean_csv,
954
+ "row_count": len(trending_repos),
955
+ "source": trending_url
956
+ }
957
+ session["final_output"] = clean_csv
958
+ else:
959
  session["extracted_data"][trending_url] = {
960
  "trending_repositories": trending_repos,
961
+ "summary": f"Found {len(trending_repos)} trending repos"
962
  }
963
+
964
+ _write_session_artifact(session, "trending_repos.csv", clean_csv)
965
+
966
+ # Completion step with final reward
967
+ complete_reward = 1.0 # Bonus for successful completion
968
+ total_reward += complete_reward
969
+ session["total_reward"] = total_reward
970
+
971
+ step_num += 1
972
+ yield _record_step(
973
+ session,
974
+ ScrapeStep(
975
+ step_number=step_num,
976
+ action="complete",
977
+ url=trending_url,
978
+ status="completed",
979
+ message=f"Successfully scraped {len(trending_repos)} repos with reward {total_reward:.2f}",
980
+ reward=complete_reward,
981
+ extracted_data={"total_reward": total_reward, "repos_found": len(trending_repos)},
982
+ timestamp=_now_iso(),
983
+ ),
984
+ )
985
 
986
 
987
  async def _scrape_single_page(
 
1190
  message=(
1191
  f"Enabled plugins: {enabled_plugins}" if enabled_plugins else "No plugins enabled"
1192
  ),
1193
+ reward=0.1 if enabled_plugins else 0.0, # Small reward for plugin setup
1194
  extracted_data={
1195
  "requested": request.enable_plugins,
1196
  "enabled": enabled_plugins,
 
1217
  action="mcp_search",
1218
  status="completed",
1219
  message="Resolved non-URL assets using search/discovery plugin logic",
1220
+ reward=0.2, # Reward for successful discovery
1221
  extracted_data={"discoveries": discoveries, "resolved_assets": resolved_assets},
1222
  timestamp=_now_iso(),
1223
  ),
 
1265
  action="planner",
1266
  status="completed",
1267
  message=f"Planner created execution plan for {len(resolved_assets)} assets",
1268
+ reward=0.15, # Reward for planning
1269
  extracted_data={
1270
  "assets": resolved_assets,
1271
  "instructions": request.instructions,
 
1315
  action="planner_python",
1316
  status="completed",
1317
  message="Planner agent executed sandbox Python code",
1318
+ reward=0.1, # Reward for sandbox execution
1319
  extracted_data=planner_sandbox.output,
1320
  timestamp=_now_iso(),
1321
  ),
 
1335
  url=url,
1336
  status="running",
1337
  message=f"Navigator selected source {idx + 1}/{len(resolved_assets)}",
1338
+ reward=0.05, # Small reward for navigator selection
1339
  timestamp=_now_iso(),
1340
  ),
1341
  )
 
1380
  url=url,
1381
  status="completed",
1382
  message="Navigator agent executed sandbox Python code",
1383
+ reward=0.1, # Reward for sandbox navigation
1384
  extracted_data=navigator_sandbox.output,
1385
  timestamp=_now_iso(),
1386
  ),