mirror of
https://github.com/bytedance/deer-flow.git
synced 2026-10-26 21:26:39 +00:00
fix(github-research): encode repository file paths in content requests (#7018)
Preserve filename delimiters and literal percent escapes before either HTTP transport builds a Contents API request. Add offline regression coverage for requests and the urllib fallback.
This commit is contained in:
parent
7e22e42365
commit
63ccc6ebfb
@ -1437,6 +1437,8 @@ Custom skill history preserves Unicode line separators inside saved content and
|
||||
The bundled `github-deep-research` API client also works without `requests`, using
|
||||
Python's standard-library HTTP client. Its fallback preserves spaces, Unicode, and
|
||||
reserved characters in search queries and label filters.
|
||||
File reads accept raw repository-relative paths and preserve spaces, Unicode,
|
||||
`#`, `?`, and literal percent signs with either HTTP client.
|
||||
|
||||
Users can explicitly activate an enabled skill for a single turn by starting the request with `/skill-name`, for example `/data-analysis analyze uploads/foo.csv`. DeerFlow loads that skill's `SKILL.md` as hidden current-turn context while leaving the base prompt limited to skill metadata. Slash activation respects disabled skills, custom-agent skill whitelists, and existing channel commands such as `/new` and `/help`.
|
||||
|
||||
|
||||
@ -8,6 +8,7 @@ import os
|
||||
import json
|
||||
import sys
|
||||
from typing import Any, Dict, List, Optional
|
||||
from urllib.parse import quote
|
||||
|
||||
try:
|
||||
import requests
|
||||
@ -113,10 +114,10 @@ class GitHubAPI:
|
||||
raise
|
||||
|
||||
def get_file_content(self, owner: str, repo: str, path: str) -> str:
|
||||
"""Get content of a specific file."""
|
||||
"""Get content of a file using its raw repository-relative path."""
|
||||
try:
|
||||
return self._get(
|
||||
f"/repos/{owner}/{repo}/contents/{path}",
|
||||
f"/repos/{owner}/{repo}/contents/{quote(path, safe='/')}",
|
||||
accept="application/vnd.github.raw",
|
||||
)
|
||||
except Exception as e:
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
"""Exercise the GitHub research client's dependency-free HTTP fallback."""
|
||||
"""Exercise the GitHub research client's HTTP transports without network IO."""
|
||||
|
||||
import http.client
|
||||
import io
|
||||
@ -37,6 +37,54 @@ def fallback_client(monkeypatch):
|
||||
return module["GitHubAPI"](), captured
|
||||
|
||||
|
||||
@pytest.fixture(params=["requests", "urllib"])
|
||||
def file_content_client(request, monkeypatch):
|
||||
if request.param == "urllib":
|
||||
return request.getfixturevalue("fallback_client")
|
||||
|
||||
requests = pytest.importorskip("requests")
|
||||
script = (
|
||||
Path(__file__).resolve().parents[2]
|
||||
/ "skills/public/github-deep-research/scripts/github_api.py"
|
||||
)
|
||||
module = runpy.run_path(str(script))
|
||||
captured = {}
|
||||
|
||||
def fake_send(session, prepared_request, **kwargs):
|
||||
captured["url"] = prepared_request.url
|
||||
response = requests.Response()
|
||||
response.status_code = 200
|
||||
response._content = b'{"ok": true}'
|
||||
return response
|
||||
|
||||
monkeypatch.setattr(requests.Session, "send", fake_send)
|
||||
return module["GitHubAPI"](), captured
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("path", "encoded_path"),
|
||||
[
|
||||
("docs/C# guide.md", "docs/C%23%20guide.md"),
|
||||
("docs/query?draft.md", "docs/query%3Fdraft.md"),
|
||||
("docs/literal%20name.md", "docs/literal%2520name.md"),
|
||||
("文档/入门 guide.md", "%E6%96%87%E6%A1%A3/%E5%85%A5%E9%97%A8%20guide.md"),
|
||||
("docs/file name.md", "docs/file%20name.md"),
|
||||
("src/nested/README.md", "src/nested/README.md"),
|
||||
],
|
||||
)
|
||||
def test_file_content_preserves_repository_path(
|
||||
file_content_client, path, encoded_path
|
||||
):
|
||||
client, captured = file_content_client
|
||||
|
||||
assert client.get_file_content("owner", "repo", path) == '{"ok": true}'
|
||||
|
||||
url = urlsplit(captured["url"])
|
||||
assert url.path == f"/repos/owner/repo/contents/{encoded_path}"
|
||||
assert url.query == ""
|
||||
assert url.fragment == ""
|
||||
|
||||
|
||||
@pytest.mark.parametrize("query", ["bug fix", "C++ & retry#fragment", "模型请求"])
|
||||
def test_fallback_search_preserves_query(fallback_client, query):
|
||||
client, captured = fallback_client
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user