Henri Bonamy commited on
Commit
8406ff4
·
1 Parent(s): 296641b

Added tool to go from draft to open PR, enabling merging + minor improvements

Browse files
Files changed (1) hide show
  1. agent/tools/hf_repo_git_tool.py +67 -13
agent/tools/hf_repo_git_tool.py CHANGED
@@ -16,7 +16,7 @@ OperationType = Literal[
16
  "create_branch", "delete_branch",
17
  "create_tag", "delete_tag",
18
  "list_refs",
19
- "create_pr", "list_prs", "get_pr", "merge_pr", "close_pr", "comment_pr",
20
  "create_repo", "update_repo",
21
  ]
22
 
@@ -59,6 +59,7 @@ class HfRepoGitTool:
59
  "merge_pr": self._merge_pr,
60
  "close_pr": self._close_pr,
61
  "comment_pr": self._comment_pr,
 
62
  "create_repo": self._create_repo,
63
  "update_repo": self._update_repo,
64
  }
@@ -88,9 +89,10 @@ class HfRepoGitTool:
88
  - `list_refs`: `{"operation": "list_refs", "repo_id": "..."}`
89
 
90
  **PRs:**
91
- - `create_pr`: `{"operation": "create_pr", "repo_id": "...", "title": "..."}`
92
- - `list_prs`: `{"operation": "list_prs", "repo_id": "..."}`
93
- - `get_pr`: `{"operation": "get_pr", "repo_id": "...", "pr_num": 1}`
 
94
  - `merge_pr`: `{"operation": "merge_pr", "repo_id": "...", "pr_num": 1}`
95
  - `close_pr`: `{"operation": "close_pr", "repo_id": "...", "pr_num": 1}`
96
  - `comment_pr`: `{"operation": "comment_pr", "repo_id": "...", "pr_num": 1, "comment": "..."}`
@@ -268,7 +270,7 @@ class HfRepoGitTool:
268
 
269
  url = f"{_build_repo_url(repo_id, repo_type)}/discussions/{result.num}"
270
  return {
271
- "formatted": f"**PR #{result.num} created:** {title}\n{url}\n\nAdd commits via upload with revision=\"refs/pr/{result.num}\"",
272
  "totalResults": 1,
273
  "resultsShared": 1,
274
  }
@@ -296,9 +298,16 @@ class HfRepoGitTool:
296
  lines = [f"**{repo_id}** - {len(discussions)} discussions", f"{url}/discussions", ""]
297
 
298
  for d in discussions[:20]:
299
- emoji = "🟢" if d.status == "open" else "🔴"
 
 
 
 
 
 
 
300
  type_label = "PR" if d.is_pull_request else "D"
301
- lines.append(f"{emoji} #{d.num} [{type_label}] {d.title}")
302
 
303
  return {"formatted": "\n".join(lines), "totalResults": len(discussions), "resultsShared": min(20, len(discussions))}
304
 
@@ -322,7 +331,13 @@ class HfRepoGitTool:
322
  )
323
 
324
  url = f"{_build_repo_url(repo_id, repo_type)}/discussions/{pr_num}"
325
- status = "🟢 Open" if pr.status == "open" else "🔴 Closed"
 
 
 
 
 
 
326
  type_label = "Pull Request" if pr.is_pull_request else "Discussion"
327
 
328
  lines = [
@@ -333,7 +348,10 @@ class HfRepoGitTool:
333
  ]
334
 
335
  if pr.is_pull_request:
336
- lines.append(f"\nTo add commits: upload with revision=\"refs/pr/{pr_num}\"")
 
 
 
337
 
338
  return {"formatted": "\n".join(lines), "totalResults": 1, "resultsShared": 1}
339
 
@@ -411,6 +429,34 @@ class HfRepoGitTool:
411
  url = f"{_build_repo_url(repo_id, repo_type)}/discussions/{pr_num}"
412
  return {"formatted": f"**Comment added to #{pr_num}**\n{url}", "totalResults": 1, "resultsShared": 1}
413
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
414
  # =========================================================================
415
  # REPO MANAGEMENT
416
  # =========================================================================
@@ -490,7 +536,7 @@ HF_REPO_GIT_TOOL_SPEC = {
490
  "## Operations\n"
491
  "**Branches:** create_branch, delete_branch, list_refs\n"
492
  "**Tags:** create_tag, delete_tag\n"
493
- "**PRs:** create_pr, list_prs, get_pr, merge_pr, close_pr, comment_pr\n"
494
  "**Repo:** create_repo, update_repo\n\n"
495
  "## Use when\n"
496
  "- Creating feature branches for experiments\n"
@@ -504,14 +550,17 @@ HF_REPO_GIT_TOOL_SPEC = {
504
  '{"operation": "create_branch", "repo_id": "my-model", "branch": "experiment-v2"}\n'
505
  '{"operation": "create_tag", "repo_id": "my-model", "tag": "v1.0", "revision": "main"}\n'
506
  '{"operation": "create_pr", "repo_id": "org/model", "title": "Fix tokenizer config"}\n'
 
507
  '{"operation": "merge_pr", "repo_id": "my-model", "pr_num": 3}\n'
508
  '{"operation": "create_repo", "repo_id": "my-new-model", "private": true}\n'
509
  '{"operation": "update_repo", "repo_id": "my-model", "gated": "auto"}\n\n'
510
  "## PR Workflow\n"
511
- "1. create_pr → creates empty draft PR\n"
512
  "2. Upload files with revision='refs/pr/N' to add commits\n"
513
- "3. merge_pr when ready\n\n"
 
514
  "## Notes\n"
 
515
  "- delete_branch, delete_tag, merge_pr, create_repo, update_repo require approval\n"
516
  "- For spaces, create_repo needs space_sdk (gradio/streamlit/docker/static)\n"
517
  "- gated options: 'auto' (instant), 'manual' (review), false (open)\n"
@@ -524,7 +573,7 @@ HF_REPO_GIT_TOOL_SPEC = {
524
  "enum": [
525
  "create_branch", "delete_branch",
526
  "create_tag", "delete_tag", "list_refs",
527
- "create_pr", "list_prs", "get_pr", "merge_pr", "close_pr", "comment_pr",
528
  "create_repo", "update_repo",
529
  ],
530
  "description": "Operation to execute",
@@ -579,6 +628,11 @@ HF_REPO_GIT_TOOL_SPEC = {
579
  "enum": ["open", "closed", "all"],
580
  "description": "Filter PRs by status (list_prs)",
581
  },
 
 
 
 
 
582
  "private": {
583
  "type": "boolean",
584
  "description": "Make repo private (create_repo, update_repo)",
 
16
  "create_branch", "delete_branch",
17
  "create_tag", "delete_tag",
18
  "list_refs",
19
+ "create_pr", "list_prs", "get_pr", "merge_pr", "close_pr", "comment_pr", "change_pr_status",
20
  "create_repo", "update_repo",
21
  ]
22
 
 
59
  "merge_pr": self._merge_pr,
60
  "close_pr": self._close_pr,
61
  "comment_pr": self._comment_pr,
62
+ "change_pr_status": self._change_pr_status,
63
  "create_repo": self._create_repo,
64
  "update_repo": self._update_repo,
65
  }
 
89
  - `list_refs`: `{"operation": "list_refs", "repo_id": "..."}`
90
 
91
  **PRs:**
92
+ - `create_pr`: `{"operation": "create_pr", "repo_id": "...", "title": "..."}` (creates draft PR)
93
+ - `list_prs`: `{"operation": "list_prs", "repo_id": "..."}` (shows status: draft/open/merged/closed)
94
+ - `get_pr`: `{"operation": "get_pr", "repo_id": "...", "pr_num": 1}` (shows status)
95
+ - `change_pr_status`: `{"operation": "change_pr_status", "repo_id": "...", "pr_num": 1, "new_status": "open"}` (change draft to open)
96
  - `merge_pr`: `{"operation": "merge_pr", "repo_id": "...", "pr_num": 1}`
97
  - `close_pr`: `{"operation": "close_pr", "repo_id": "...", "pr_num": 1}`
98
  - `comment_pr`: `{"operation": "comment_pr", "repo_id": "...", "pr_num": 1, "comment": "..."}`
 
270
 
271
  url = f"{_build_repo_url(repo_id, repo_type)}/discussions/{result.num}"
272
  return {
273
+ "formatted": f"**Draft PR #{result.num} created:** {title}\n{url}\n\nAdd commits via upload with revision=\"refs/pr/{result.num}\"",
274
  "totalResults": 1,
275
  "resultsShared": 1,
276
  }
 
298
  lines = [f"**{repo_id}** - {len(discussions)} discussions", f"{url}/discussions", ""]
299
 
300
  for d in discussions[:20]:
301
+ if d.status == "draft":
302
+ status_label = "[DRAFT]"
303
+ elif d.status == "open":
304
+ status_label = "[OPEN]"
305
+ elif d.status == "merged":
306
+ status_label = "[MERGED]"
307
+ else:
308
+ status_label = "[CLOSED]"
309
  type_label = "PR" if d.is_pull_request else "D"
310
+ lines.append(f"{status_label} #{d.num} [{type_label}] {d.title}")
311
 
312
  return {"formatted": "\n".join(lines), "totalResults": len(discussions), "resultsShared": min(20, len(discussions))}
313
 
 
331
  )
332
 
333
  url = f"{_build_repo_url(repo_id, repo_type)}/discussions/{pr_num}"
334
+ status_map = {
335
+ "draft": "Draft",
336
+ "open": "Open",
337
+ "merged": "Merged",
338
+ "closed": "Closed"
339
+ }
340
+ status = status_map.get(pr.status, pr.status.capitalize())
341
  type_label = "Pull Request" if pr.is_pull_request else "Discussion"
342
 
343
  lines = [
 
348
  ]
349
 
350
  if pr.is_pull_request:
351
+ if pr.status == "draft":
352
+ lines.append(f"\nTo add commits: upload with revision=\"refs/pr/{pr_num}\"")
353
+ elif pr.status == "open":
354
+ lines.append(f"\nTo add commits: upload with revision=\"refs/pr/{pr_num}\"")
355
 
356
  return {"formatted": "\n".join(lines), "totalResults": 1, "resultsShared": 1}
357
 
 
429
  url = f"{_build_repo_url(repo_id, repo_type)}/discussions/{pr_num}"
430
  return {"formatted": f"**Comment added to #{pr_num}**\n{url}", "totalResults": 1, "resultsShared": 1}
431
 
432
+ async def _change_pr_status(self, args: Dict[str, Any]) -> ToolResult:
433
+ """Change PR/discussion status (mainly to convert draft to open)."""
434
+ repo_id = args.get("repo_id")
435
+ pr_num = args.get("pr_num")
436
+ new_status = args.get("new_status")
437
+
438
+ if not repo_id:
439
+ return self._error("repo_id is required")
440
+ if not pr_num:
441
+ return self._error("pr_num is required")
442
+ if not new_status:
443
+ return self._error("new_status is required (open or closed)")
444
+
445
+ repo_type = args.get("repo_type", "model")
446
+ comment = args.get("comment", "")
447
+
448
+ await _async_call(
449
+ self.api.change_discussion_status,
450
+ repo_id=repo_id,
451
+ discussion_num=int(pr_num),
452
+ new_status=new_status,
453
+ comment=comment,
454
+ repo_type=repo_type,
455
+ )
456
+
457
+ url = f"{_build_repo_url(repo_id, repo_type)}/discussions/{pr_num}"
458
+ return {"formatted": f"**PR #{pr_num} status changed to {new_status}**\n{url}", "totalResults": 1, "resultsShared": 1}
459
+
460
  # =========================================================================
461
  # REPO MANAGEMENT
462
  # =========================================================================
 
536
  "## Operations\n"
537
  "**Branches:** create_branch, delete_branch, list_refs\n"
538
  "**Tags:** create_tag, delete_tag\n"
539
+ "**PRs:** create_pr, list_prs, get_pr, merge_pr, close_pr, comment_pr, change_pr_status\n"
540
  "**Repo:** create_repo, update_repo\n\n"
541
  "## Use when\n"
542
  "- Creating feature branches for experiments\n"
 
550
  '{"operation": "create_branch", "repo_id": "my-model", "branch": "experiment-v2"}\n'
551
  '{"operation": "create_tag", "repo_id": "my-model", "tag": "v1.0", "revision": "main"}\n'
552
  '{"operation": "create_pr", "repo_id": "org/model", "title": "Fix tokenizer config"}\n'
553
+ '{"operation": "change_pr_status", "repo_id": "my-model", "pr_num": 1, "new_status": "open"}\n'
554
  '{"operation": "merge_pr", "repo_id": "my-model", "pr_num": 3}\n'
555
  '{"operation": "create_repo", "repo_id": "my-new-model", "private": true}\n'
556
  '{"operation": "update_repo", "repo_id": "my-model", "gated": "auto"}\n\n'
557
  "## PR Workflow\n"
558
+ "1. create_pr → creates draft PR (empty by default)\n"
559
  "2. Upload files with revision='refs/pr/N' to add commits\n"
560
+ "3. change_pr_status with new_status='open' to publish (convert draft to open)\n"
561
+ "4. merge_pr when ready\n\n"
562
  "## Notes\n"
563
+ "- PR status: draft (default), open, merged, closed\n"
564
  "- delete_branch, delete_tag, merge_pr, create_repo, update_repo require approval\n"
565
  "- For spaces, create_repo needs space_sdk (gradio/streamlit/docker/static)\n"
566
  "- gated options: 'auto' (instant), 'manual' (review), false (open)\n"
 
573
  "enum": [
574
  "create_branch", "delete_branch",
575
  "create_tag", "delete_tag", "list_refs",
576
+ "create_pr", "list_prs", "get_pr", "merge_pr", "close_pr", "comment_pr", "change_pr_status",
577
  "create_repo", "update_repo",
578
  ],
579
  "description": "Operation to execute",
 
628
  "enum": ["open", "closed", "all"],
629
  "description": "Filter PRs by status (list_prs)",
630
  },
631
+ "new_status": {
632
+ "type": "string",
633
+ "enum": ["open", "closed"],
634
+ "description": "New status for PR/discussion (change_pr_status)",
635
+ },
636
  "private": {
637
  "type": "boolean",
638
  "description": "Make repo private (create_repo, update_repo)",