gitcode-api 1.2.9__tar.gz → 1.2.10__tar.gz

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.
Files changed (45) hide show
  1. {gitcode_api-1.2.9 → gitcode_api-1.2.10}/PKG-INFO +35 -25
  2. {gitcode_api-1.2.9 → gitcode_api-1.2.10}/README.md +34 -24
  3. {gitcode_api-1.2.9 → gitcode_api-1.2.10}/gitcode_api/llm/jiuwen.py +1 -0
  4. {gitcode_api-1.2.9 → gitcode_api-1.2.10}/gitcode_api/llm/openai.py +14 -13
  5. gitcode_api-1.2.10/gitcode_api/version.txt +1 -0
  6. {gitcode_api-1.2.9 → gitcode_api-1.2.10}/gitcode_api.egg-info/PKG-INFO +35 -25
  7. {gitcode_api-1.2.9 → gitcode_api-1.2.10}/pyproject.toml +1 -1
  8. {gitcode_api-1.2.9 → gitcode_api-1.2.10}/tests/test_llm_tools.py +3 -16
  9. gitcode_api-1.2.9/gitcode_api/version.txt +0 -1
  10. {gitcode_api-1.2.9 → gitcode_api-1.2.10}/LICENSE +0 -0
  11. {gitcode_api-1.2.9 → gitcode_api-1.2.10}/gitcode_api/__init__.py +0 -0
  12. {gitcode_api-1.2.9 → gitcode_api-1.2.10}/gitcode_api/__main__.py +0 -0
  13. {gitcode_api-1.2.9 → gitcode_api-1.2.10}/gitcode_api/_base_client.py +0 -0
  14. {gitcode_api-1.2.9 → gitcode_api-1.2.10}/gitcode_api/_base_resource.py +0 -0
  15. {gitcode_api-1.2.9 → gitcode_api-1.2.10}/gitcode_api/_cli_banner.py +0 -0
  16. {gitcode_api-1.2.9 → gitcode_api-1.2.10}/gitcode_api/_client.py +0 -0
  17. {gitcode_api-1.2.9 → gitcode_api-1.2.10}/gitcode_api/_exceptions.py +0 -0
  18. {gitcode_api-1.2.9 → gitcode_api-1.2.10}/gitcode_api/_models.py +0 -0
  19. {gitcode_api-1.2.9 → gitcode_api-1.2.10}/gitcode_api/cli.py +0 -0
  20. {gitcode_api-1.2.9 → gitcode_api-1.2.10}/gitcode_api/llm/__init__.py +0 -0
  21. {gitcode_api-1.2.9 → gitcode_api-1.2.10}/gitcode_api/llm/_tool.py +0 -0
  22. {gitcode_api-1.2.9 → gitcode_api-1.2.10}/gitcode_api/llm/mcp.py +0 -0
  23. {gitcode_api-1.2.9 → gitcode_api-1.2.10}/gitcode_api/py.typed +0 -0
  24. {gitcode_api-1.2.9 → gitcode_api-1.2.10}/gitcode_api/resources/__init__.py +0 -0
  25. {gitcode_api-1.2.9 → gitcode_api-1.2.10}/gitcode_api/resources/_shared.py +0 -0
  26. {gitcode_api-1.2.9 → gitcode_api-1.2.10}/gitcode_api/resources/account.py +0 -0
  27. {gitcode_api-1.2.9 → gitcode_api-1.2.10}/gitcode_api/resources/collaboration.py +0 -0
  28. {gitcode_api-1.2.9 → gitcode_api-1.2.10}/gitcode_api/resources/misc.py +0 -0
  29. {gitcode_api-1.2.9 → gitcode_api-1.2.10}/gitcode_api/resources/repositories.py +0 -0
  30. {gitcode_api-1.2.9 → gitcode_api-1.2.10}/gitcode_api/run_mcp.py +0 -0
  31. {gitcode_api-1.2.9 → gitcode_api-1.2.10}/gitcode_api.egg-info/SOURCES.txt +0 -0
  32. {gitcode_api-1.2.9 → gitcode_api-1.2.10}/gitcode_api.egg-info/dependency_links.txt +0 -0
  33. {gitcode_api-1.2.9 → gitcode_api-1.2.10}/gitcode_api.egg-info/entry_points.txt +0 -0
  34. {gitcode_api-1.2.9 → gitcode_api-1.2.10}/gitcode_api.egg-info/requires.txt +0 -0
  35. {gitcode_api-1.2.9 → gitcode_api-1.2.10}/gitcode_api.egg-info/top_level.txt +0 -0
  36. {gitcode_api-1.2.9 → gitcode_api-1.2.10}/setup.cfg +0 -0
  37. {gitcode_api-1.2.9 → gitcode_api-1.2.10}/tests/test_base_client.py +0 -0
  38. {gitcode_api-1.2.9 → gitcode_api-1.2.10}/tests/test_build_manifest.py +0 -0
  39. {gitcode_api-1.2.9 → gitcode_api-1.2.10}/tests/test_cli.py +0 -0
  40. {gitcode_api-1.2.9 → gitcode_api-1.2.10}/tests/test_client.py +0 -0
  41. {gitcode_api-1.2.9 → gitcode_api-1.2.10}/tests/test_models.py +0 -0
  42. {gitcode_api-1.2.9 → gitcode_api-1.2.10}/tests/test_resources_account.py +0 -0
  43. {gitcode_api-1.2.9 → gitcode_api-1.2.10}/tests/test_resources_collaboration.py +0 -0
  44. {gitcode_api-1.2.9 → gitcode_api-1.2.10}/tests/test_resources_misc.py +0 -0
  45. {gitcode_api-1.2.9 → gitcode_api-1.2.10}/tests/test_resources_repositories.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gitcode-api
3
- Version: 1.2.9
3
+ Version: 1.2.10
4
4
  Summary: Easy to use Python SDK for the GitCode REST API. Providing builtin CLI tool, and optional LLM integration (MCP, OpenAI tool, and openJiuwen tool) for agents. Community-maintained.
5
5
  Author-email: Hugo Huang <hugo@hugohuang.com>
6
6
  License-Expression: MIT
@@ -240,11 +240,11 @@ The `gitcode_api.llm` module exposes a single logical tool, **`gitcode_api_tool`
240
240
  | `params` | Keyword arguments for the method as a JSON object; omitted or `null` is treated as `{}`. |
241
241
  | `help` | When `true`, returns formatted help (available methods or a target signature) instead of performing a normal API call where applicable. |
242
242
 
243
- Successful results are JSON-friendly (`APIObject.to_dict()`, base64-wrapped `bytes`, and similar). Failures are returned as objects with `"error": true` and a `"message"` string (HTTP and configuration errors include extra fields when available).
243
+ Tool payloads are JSON-serialized strings: successes look like plain objects (`APIObject.to_dict()`, base64-wrapped `bytes`, and similar); failures use `"error": true`, a `"message"` string, and optional extra fields on HTTP/configuration errors.
244
244
 
245
245
  ### OpenAI tool (`GitCodeOpenAITool`)
246
246
 
247
- No extra dependencies beyond the core package. Build a Chat Completions–style tool definition with `.tool` or `.to_dict()`, then invoke the same instance with the arguments above (sync) or configure async mode for `await`.
247
+ No extra dependencies beyond the core package. Build a Chat Completions–style tool definition with `.tool` or `.to_dict()`, then invoke the same instance with the arguments above (sync) or configure async mode for `await`. Each invocation applies `json.dumps` to payload so the return type is **always `str`**. The default keyword argument `indent=2` pretty-prints JSON; pass `indent=None` for a compact single-line string.
248
248
 
249
249
  ```python
250
250
  from gitcode_api.llm import GitCodeOpenAITool
@@ -265,33 +265,43 @@ and handle tool calls directly:
265
265
 
266
266
  ```python
267
267
  import json
268
- from openai import OpenAI
269
- from gitcode_api.llm import GitCodeOpenAITool
268
+ import os
269
+ from typing import Dict, List
270
270
 
271
- tools = {
272
- "gitcode_api_tool": GitCodeOpenAITool(owner="SushiNinja", repo="GitCode-API"),
273
- }
274
- client = OpenAI(
275
- api_key="your-openai-compatible-api-key",
276
- base_url="https://your-openai-compatible-base-url/v1",
277
- )
271
+ from openai import OpenAI
278
272
 
279
- response = client.chat.completions.create(
280
- model="gpt-4.1-mini",
281
- messages=[{"role": "user", "content": "List the last 5 commits."}],
282
- tools=[tools["gitcode_api_tool"].tool],
283
- )
273
+ from gitcode_api.llm import GitCodeOpenAITool
284
274
 
285
- for tool_call in response.choices[0].message.tool_calls:
286
- selected_tool = tools[tool_call.function.name]
287
- print(f"Calling tool {tool_call.function.name}({tool_call.function.arguments}):")
288
- print("---result---")
289
- print(selected_tool(**json.loads(tool_call.function.arguments)))
290
- print("---result---")
275
+ MESSAGE_SEP = "\n" + "=" * 60 + "\n"
276
+ USER_QUERY = "List the repos owned by SushiNinja."
277
+ CONVERSATION: List[Dict[str, str]] = [dict(role="user", content=USER_QUERY)]
278
+
279
+ tools = {"gitcode_api_tool": GitCodeOpenAITool()}
280
+ client = OpenAI()
281
+
282
+ print("U:\n" + USER_QUERY + MESSAGE_SEP)
283
+ while True:
284
+ response = (
285
+ client.chat.completions.create(
286
+ model="gpt-5.4-nano",
287
+ messages=CONVERSATION,
288
+ tools=[tools["gitcode_api_tool"].tool],
289
+ )
290
+ .choices[0]
291
+ .message
292
+ )
293
+ CONVERSATION.append(response.to_dict())
294
+ print("A:\n" + (response.content or ""))
295
+ for tool_call in response.tool_calls or []:
296
+ selected_tool = tools[tool_call.function.name]
297
+ result = selected_tool(**json.loads(tool_call.function.arguments))
298
+ CONVERSATION.append(dict(role="tool", tool_call_id=tool_call.id, content=result))
299
+ print(f"<Calling tool {tool_call.function.name}({tool_call.function.arguments})>")
300
+ print(MESSAGE_SEP)
301
+ if not response.tool_calls:
302
+ break
291
303
  ```
292
304
 
293
- Constructor options mirror `GitCode` / `AsyncGitCode`: `client=`, `async_client=`, `api_key=`, `owner=`, `repo=`, `base_url=`, `timeout=`, and `decrypt=`. For dict-driven setups that reserve the name `async`, you may pass `**{"async": True}` instead of `async_mode=True` (but not both).
294
-
295
305
  ### MCP server and MCP tool (FastMCP)
296
306
 
297
307
  [MCP](https://modelcontextprotocol.io) integration uses [FastMCP](https://github.com/jlowin/fastmcp). Install the optional extra (requires **Python 3.10+** because of the `fastmcp` dependency):
@@ -203,11 +203,11 @@ The `gitcode_api.llm` module exposes a single logical tool, **`gitcode_api_tool`
203
203
  | `params` | Keyword arguments for the method as a JSON object; omitted or `null` is treated as `{}`. |
204
204
  | `help` | When `true`, returns formatted help (available methods or a target signature) instead of performing a normal API call where applicable. |
205
205
 
206
- Successful results are JSON-friendly (`APIObject.to_dict()`, base64-wrapped `bytes`, and similar). Failures are returned as objects with `"error": true` and a `"message"` string (HTTP and configuration errors include extra fields when available).
206
+ Tool payloads are JSON-serialized strings: successes look like plain objects (`APIObject.to_dict()`, base64-wrapped `bytes`, and similar); failures use `"error": true`, a `"message"` string, and optional extra fields on HTTP/configuration errors.
207
207
 
208
208
  ### OpenAI tool (`GitCodeOpenAITool`)
209
209
 
210
- No extra dependencies beyond the core package. Build a Chat Completions–style tool definition with `.tool` or `.to_dict()`, then invoke the same instance with the arguments above (sync) or configure async mode for `await`.
210
+ No extra dependencies beyond the core package. Build a Chat Completions–style tool definition with `.tool` or `.to_dict()`, then invoke the same instance with the arguments above (sync) or configure async mode for `await`. Each invocation applies `json.dumps` to payload so the return type is **always `str`**. The default keyword argument `indent=2` pretty-prints JSON; pass `indent=None` for a compact single-line string.
211
211
 
212
212
  ```python
213
213
  from gitcode_api.llm import GitCodeOpenAITool
@@ -228,33 +228,43 @@ and handle tool calls directly:
228
228
 
229
229
  ```python
230
230
  import json
231
- from openai import OpenAI
232
- from gitcode_api.llm import GitCodeOpenAITool
231
+ import os
232
+ from typing import Dict, List
233
233
 
234
- tools = {
235
- "gitcode_api_tool": GitCodeOpenAITool(owner="SushiNinja", repo="GitCode-API"),
236
- }
237
- client = OpenAI(
238
- api_key="your-openai-compatible-api-key",
239
- base_url="https://your-openai-compatible-base-url/v1",
240
- )
234
+ from openai import OpenAI
241
235
 
242
- response = client.chat.completions.create(
243
- model="gpt-4.1-mini",
244
- messages=[{"role": "user", "content": "List the last 5 commits."}],
245
- tools=[tools["gitcode_api_tool"].tool],
246
- )
236
+ from gitcode_api.llm import GitCodeOpenAITool
247
237
 
248
- for tool_call in response.choices[0].message.tool_calls:
249
- selected_tool = tools[tool_call.function.name]
250
- print(f"Calling tool {tool_call.function.name}({tool_call.function.arguments}):")
251
- print("---result---")
252
- print(selected_tool(**json.loads(tool_call.function.arguments)))
253
- print("---result---")
238
+ MESSAGE_SEP = "\n" + "=" * 60 + "\n"
239
+ USER_QUERY = "List the repos owned by SushiNinja."
240
+ CONVERSATION: List[Dict[str, str]] = [dict(role="user", content=USER_QUERY)]
241
+
242
+ tools = {"gitcode_api_tool": GitCodeOpenAITool()}
243
+ client = OpenAI()
244
+
245
+ print("U:\n" + USER_QUERY + MESSAGE_SEP)
246
+ while True:
247
+ response = (
248
+ client.chat.completions.create(
249
+ model="gpt-5.4-nano",
250
+ messages=CONVERSATION,
251
+ tools=[tools["gitcode_api_tool"].tool],
252
+ )
253
+ .choices[0]
254
+ .message
255
+ )
256
+ CONVERSATION.append(response.to_dict())
257
+ print("A:\n" + (response.content or ""))
258
+ for tool_call in response.tool_calls or []:
259
+ selected_tool = tools[tool_call.function.name]
260
+ result = selected_tool(**json.loads(tool_call.function.arguments))
261
+ CONVERSATION.append(dict(role="tool", tool_call_id=tool_call.id, content=result))
262
+ print(f"<Calling tool {tool_call.function.name}({tool_call.function.arguments})>")
263
+ print(MESSAGE_SEP)
264
+ if not response.tool_calls:
265
+ break
254
266
  ```
255
267
 
256
- Constructor options mirror `GitCode` / `AsyncGitCode`: `client=`, `async_client=`, `api_key=`, `owner=`, `repo=`, `base_url=`, `timeout=`, and `decrypt=`. For dict-driven setups that reserve the name `async`, you may pass `**{"async": True}` instead of `async_mode=True` (but not both).
257
-
258
268
  ### MCP server and MCP tool (FastMCP)
259
269
 
260
270
  [MCP](https://modelcontextprotocol.io) integration uses [FastMCP](https://github.com/jlowin/fastmcp). Install the optional extra (requires **Python 3.10+** because of the `fastmcp` dependency):
@@ -11,6 +11,7 @@ from ._tool import TOOL_DESCRIPTION, TOOL_NAME, TOOL_PARAMETERS, GitCodeLLMTool
11
11
  if TYPE_CHECKING:
12
12
  from openjiuwen.core.foundation.tool import LocalFunction
13
13
 
14
+
14
15
  def _missing_openjiuwen_error() -> ImportError:
15
16
  return ImportError(
16
17
  "The openJiuwen tool support requires the optional dependency: pip install openjiuwen. "
@@ -1,7 +1,8 @@
1
1
  """OpenAI tool adapter for the GitCode SDK."""
2
2
 
3
+ import json
3
4
  from functools import cached_property
4
- from typing import Any, Dict, Optional
5
+ from typing import Any, Coroutine, Dict, Union
5
6
 
6
7
  from ._tool import TOOL_DESCRIPTION, TOOL_NAME, TOOL_PARAMETERS, GitCodeLLMTool
7
8
 
@@ -10,25 +11,21 @@ class GitCodeOpenAITool(GitCodeLLMTool):
10
11
  """OpenAI-compatible callable tool for invoking GitCode SDK resources.
11
12
 
12
13
  :param async_mode: When true, calling the instance returns the async tool coroutine.
13
- :param kwargs: Forwarded to :class:`gitcode_api.llm.GitCodeLLMTool`. ``{"async": True}``
14
- is also accepted for frameworks that construct tools from dictionaries.
14
+ :param indent: ``indent`` argument passed to :func:`json.dumps` when serializing
15
+ invocation results (default ``2``).
16
+ :param kwargs: Passed to :class:`gitcode_api.llm.GitCodeLLMTool` ---
17
+ ``client``, ``async_client``, ``api_key``, ``owner``, ``repo``, ``base_url``, ``timeout``, ``decrypt``.
15
18
  """
16
19
 
17
20
  name = TOOL_NAME
18
21
  description = TOOL_DESCRIPTION
19
22
  parameters = TOOL_PARAMETERS
20
23
 
21
- def __init__(self, async_mode: Optional[bool] = None, **kwargs) -> None:
24
+ def __init__(self, async_mode: bool = False, indent: int = 2, **kwargs) -> None:
22
25
  """Create an OpenAI tool wrapper."""
23
- async_kw = kwargs.pop("async", None)
24
- if async_mode is None:
25
- async_mode = bool(async_kw)
26
- elif async_kw is not None:
27
- raise TypeError("Pass only one of async_mode or async")
26
+ self.indent = indent
28
27
  self.async_mode = bool(async_mode)
29
28
  super().__init__(**kwargs)
30
- if self.async_mode:
31
- self.__call__ = self.__async_call__ # type: ignore[method-assign]
32
29
 
33
30
  @cached_property
34
31
  def tool(self) -> Dict[str, Any]:
@@ -46,11 +43,15 @@ class GitCodeOpenAITool(GitCodeLLMTool):
46
43
  """Return this tool in OpenAI Chat Completions tool format."""
47
44
  return self.tool
48
45
 
49
- def __call__(self, *args: Any, **kwargs) -> Any:
46
+ async def __async_call__(self, *args, **kwargs) -> str:
47
+ result = await super().__async_call__(*args, **kwargs)
48
+ return json.dumps(result, ensure_ascii=False, indent=self.indent)
49
+
50
+ def __call__(self, *args, **kwargs) -> Union[str, Coroutine[Any, Any, str]]:
50
51
  """Invoke the configured sync or async tool callable."""
51
52
  if self.async_mode:
52
53
  return self.__async_call__(*args, **kwargs)
53
- return super().__call__(*args, **kwargs)
54
+ return json.dumps(super().__call__(*args, **kwargs), ensure_ascii=False, indent=self.indent)
54
55
 
55
56
 
56
57
  __all__ = ["GitCodeOpenAITool"]
@@ -0,0 +1 @@
1
+ 1.2.10
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gitcode-api
3
- Version: 1.2.9
3
+ Version: 1.2.10
4
4
  Summary: Easy to use Python SDK for the GitCode REST API. Providing builtin CLI tool, and optional LLM integration (MCP, OpenAI tool, and openJiuwen tool) for agents. Community-maintained.
5
5
  Author-email: Hugo Huang <hugo@hugohuang.com>
6
6
  License-Expression: MIT
@@ -240,11 +240,11 @@ The `gitcode_api.llm` module exposes a single logical tool, **`gitcode_api_tool`
240
240
  | `params` | Keyword arguments for the method as a JSON object; omitted or `null` is treated as `{}`. |
241
241
  | `help` | When `true`, returns formatted help (available methods or a target signature) instead of performing a normal API call where applicable. |
242
242
 
243
- Successful results are JSON-friendly (`APIObject.to_dict()`, base64-wrapped `bytes`, and similar). Failures are returned as objects with `"error": true` and a `"message"` string (HTTP and configuration errors include extra fields when available).
243
+ Tool payloads are JSON-serialized strings: successes look like plain objects (`APIObject.to_dict()`, base64-wrapped `bytes`, and similar); failures use `"error": true`, a `"message"` string, and optional extra fields on HTTP/configuration errors.
244
244
 
245
245
  ### OpenAI tool (`GitCodeOpenAITool`)
246
246
 
247
- No extra dependencies beyond the core package. Build a Chat Completions–style tool definition with `.tool` or `.to_dict()`, then invoke the same instance with the arguments above (sync) or configure async mode for `await`.
247
+ No extra dependencies beyond the core package. Build a Chat Completions–style tool definition with `.tool` or `.to_dict()`, then invoke the same instance with the arguments above (sync) or configure async mode for `await`. Each invocation applies `json.dumps` to payload so the return type is **always `str`**. The default keyword argument `indent=2` pretty-prints JSON; pass `indent=None` for a compact single-line string.
248
248
 
249
249
  ```python
250
250
  from gitcode_api.llm import GitCodeOpenAITool
@@ -265,33 +265,43 @@ and handle tool calls directly:
265
265
 
266
266
  ```python
267
267
  import json
268
- from openai import OpenAI
269
- from gitcode_api.llm import GitCodeOpenAITool
268
+ import os
269
+ from typing import Dict, List
270
270
 
271
- tools = {
272
- "gitcode_api_tool": GitCodeOpenAITool(owner="SushiNinja", repo="GitCode-API"),
273
- }
274
- client = OpenAI(
275
- api_key="your-openai-compatible-api-key",
276
- base_url="https://your-openai-compatible-base-url/v1",
277
- )
271
+ from openai import OpenAI
278
272
 
279
- response = client.chat.completions.create(
280
- model="gpt-4.1-mini",
281
- messages=[{"role": "user", "content": "List the last 5 commits."}],
282
- tools=[tools["gitcode_api_tool"].tool],
283
- )
273
+ from gitcode_api.llm import GitCodeOpenAITool
284
274
 
285
- for tool_call in response.choices[0].message.tool_calls:
286
- selected_tool = tools[tool_call.function.name]
287
- print(f"Calling tool {tool_call.function.name}({tool_call.function.arguments}):")
288
- print("---result---")
289
- print(selected_tool(**json.loads(tool_call.function.arguments)))
290
- print("---result---")
275
+ MESSAGE_SEP = "\n" + "=" * 60 + "\n"
276
+ USER_QUERY = "List the repos owned by SushiNinja."
277
+ CONVERSATION: List[Dict[str, str]] = [dict(role="user", content=USER_QUERY)]
278
+
279
+ tools = {"gitcode_api_tool": GitCodeOpenAITool()}
280
+ client = OpenAI()
281
+
282
+ print("U:\n" + USER_QUERY + MESSAGE_SEP)
283
+ while True:
284
+ response = (
285
+ client.chat.completions.create(
286
+ model="gpt-5.4-nano",
287
+ messages=CONVERSATION,
288
+ tools=[tools["gitcode_api_tool"].tool],
289
+ )
290
+ .choices[0]
291
+ .message
292
+ )
293
+ CONVERSATION.append(response.to_dict())
294
+ print("A:\n" + (response.content or ""))
295
+ for tool_call in response.tool_calls or []:
296
+ selected_tool = tools[tool_call.function.name]
297
+ result = selected_tool(**json.loads(tool_call.function.arguments))
298
+ CONVERSATION.append(dict(role="tool", tool_call_id=tool_call.id, content=result))
299
+ print(f"<Calling tool {tool_call.function.name}({tool_call.function.arguments})>")
300
+ print(MESSAGE_SEP)
301
+ if not response.tool_calls:
302
+ break
291
303
  ```
292
304
 
293
- Constructor options mirror `GitCode` / `AsyncGitCode`: `client=`, `async_client=`, `api_key=`, `owner=`, `repo=`, `base_url=`, `timeout=`, and `decrypt=`. For dict-driven setups that reserve the name `async`, you may pass `**{"async": True}` instead of `async_mode=True` (but not both).
294
-
295
305
  ### MCP server and MCP tool (FastMCP)
296
306
 
297
307
  [MCP](https://modelcontextprotocol.io) integration uses [FastMCP](https://github.com/jlowin/fastmcp). Install the optional extra (requires **Python 3.10+** because of the `fastmcp` dependency):
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "gitcode-api"
3
- version = "1.2.9"
3
+ version = "1.2.10"
4
4
  description = "Easy to use Python SDK for the GitCode REST API. Providing builtin CLI tool, and optional LLM integration (MCP, OpenAI tool, and openJiuwen tool) for agents. Community-maintained."
5
5
  keywords = [
6
6
  "gitcode", "git", "devops", "api", "sdk", "python", "httpx", "client",
@@ -1,4 +1,5 @@
1
1
  import importlib.util
2
+ import json
2
3
  from typing import Any, Dict
3
4
 
4
5
  import httpx
@@ -44,7 +45,7 @@ def test_openai_tool_invokes_sync_client(sync_client_factory: Any) -> None:
44
45
  http_client.close()
45
46
 
46
47
  assert "/repos/SushiNinja/GitCode-API" in captured["url"]
47
- assert result == {"full_name": "SushiNinja/GitCode-API"}
48
+ assert json.loads(result) == {"full_name": "SushiNinja/GitCode-API"}
48
49
 
49
50
 
50
51
  @pytest.mark.asyncio
@@ -63,7 +64,7 @@ async def test_openai_tool_invokes_async_client(async_client_factory: Any) -> No
63
64
  await http_client.aclose()
64
65
 
65
66
  assert "/users/octocat" in captured["url"]
66
- assert result == {"login": "octocat"}
67
+ assert json.loads(result) == {"login": "octocat"}
67
68
 
68
69
 
69
70
  def test_tool_help_does_not_require_api_key(monkeypatch: Any) -> None:
@@ -129,20 +130,6 @@ def test_help_resource_index_body() -> None:
129
130
  assert f"gitcode-api://help/{name}" in body
130
131
 
131
132
 
132
- @pytest.mark.asyncio
133
- async def test_create_mcp_server_registers_help_resources() -> None:
134
- mcp = create_mcp_server()
135
- static = await mcp._list_resources_mcp()
136
- templates = await mcp._list_resource_templates_mcp()
137
- assert any(str(r.uri) == "gitcode-api://help" for r in static)
138
- assert any(
139
- "{op_type}" in str(getattr(t, "uri_template", None) or getattr(t, "uriTemplate", None)) for t in templates
140
- )
141
- read = await mcp._read_resource_mcp("gitcode-api://help/pulls")
142
- payload = read[0].content
143
- assert "Resource: pulls" in payload
144
-
145
-
146
133
  def test_mcp_registers_with_existing_server() -> None:
147
134
  class DummyMCP:
148
135
  def __init__(self) -> None:
@@ -1 +0,0 @@
1
- 1.2.9
File without changes
File without changes