gitcode-api 1.2.8__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.8 → gitcode_api-1.2.10}/PKG-INFO +62 -33
  2. {gitcode_api-1.2.8 → gitcode_api-1.2.10}/README.md +59 -30
  3. {gitcode_api-1.2.8 → gitcode_api-1.2.10}/gitcode_api/llm/__init__.py +3 -0
  4. gitcode_api-1.2.10/gitcode_api/llm/jiuwen.py +98 -0
  5. {gitcode_api-1.2.8 → gitcode_api-1.2.10}/gitcode_api/llm/openai.py +14 -13
  6. gitcode_api-1.2.10/gitcode_api/version.txt +1 -0
  7. {gitcode_api-1.2.8 → gitcode_api-1.2.10}/gitcode_api.egg-info/PKG-INFO +62 -33
  8. {gitcode_api-1.2.8 → gitcode_api-1.2.10}/gitcode_api.egg-info/SOURCES.txt +1 -0
  9. {gitcode_api-1.2.8 → gitcode_api-1.2.10}/pyproject.toml +3 -3
  10. {gitcode_api-1.2.8 → gitcode_api-1.2.10}/tests/test_llm_tools.py +55 -14
  11. gitcode_api-1.2.8/gitcode_api/version.txt +0 -1
  12. {gitcode_api-1.2.8 → gitcode_api-1.2.10}/LICENSE +0 -0
  13. {gitcode_api-1.2.8 → gitcode_api-1.2.10}/gitcode_api/__init__.py +0 -0
  14. {gitcode_api-1.2.8 → gitcode_api-1.2.10}/gitcode_api/__main__.py +0 -0
  15. {gitcode_api-1.2.8 → gitcode_api-1.2.10}/gitcode_api/_base_client.py +0 -0
  16. {gitcode_api-1.2.8 → gitcode_api-1.2.10}/gitcode_api/_base_resource.py +0 -0
  17. {gitcode_api-1.2.8 → gitcode_api-1.2.10}/gitcode_api/_cli_banner.py +0 -0
  18. {gitcode_api-1.2.8 → gitcode_api-1.2.10}/gitcode_api/_client.py +0 -0
  19. {gitcode_api-1.2.8 → gitcode_api-1.2.10}/gitcode_api/_exceptions.py +0 -0
  20. {gitcode_api-1.2.8 → gitcode_api-1.2.10}/gitcode_api/_models.py +0 -0
  21. {gitcode_api-1.2.8 → gitcode_api-1.2.10}/gitcode_api/cli.py +0 -0
  22. {gitcode_api-1.2.8 → gitcode_api-1.2.10}/gitcode_api/llm/_tool.py +0 -0
  23. {gitcode_api-1.2.8 → gitcode_api-1.2.10}/gitcode_api/llm/mcp.py +0 -0
  24. {gitcode_api-1.2.8 → gitcode_api-1.2.10}/gitcode_api/py.typed +0 -0
  25. {gitcode_api-1.2.8 → gitcode_api-1.2.10}/gitcode_api/resources/__init__.py +0 -0
  26. {gitcode_api-1.2.8 → gitcode_api-1.2.10}/gitcode_api/resources/_shared.py +0 -0
  27. {gitcode_api-1.2.8 → gitcode_api-1.2.10}/gitcode_api/resources/account.py +0 -0
  28. {gitcode_api-1.2.8 → gitcode_api-1.2.10}/gitcode_api/resources/collaboration.py +0 -0
  29. {gitcode_api-1.2.8 → gitcode_api-1.2.10}/gitcode_api/resources/misc.py +0 -0
  30. {gitcode_api-1.2.8 → gitcode_api-1.2.10}/gitcode_api/resources/repositories.py +0 -0
  31. {gitcode_api-1.2.8 → gitcode_api-1.2.10}/gitcode_api/run_mcp.py +0 -0
  32. {gitcode_api-1.2.8 → gitcode_api-1.2.10}/gitcode_api.egg-info/dependency_links.txt +0 -0
  33. {gitcode_api-1.2.8 → gitcode_api-1.2.10}/gitcode_api.egg-info/entry_points.txt +0 -0
  34. {gitcode_api-1.2.8 → gitcode_api-1.2.10}/gitcode_api.egg-info/requires.txt +0 -0
  35. {gitcode_api-1.2.8 → gitcode_api-1.2.10}/gitcode_api.egg-info/top_level.txt +0 -0
  36. {gitcode_api-1.2.8 → gitcode_api-1.2.10}/setup.cfg +0 -0
  37. {gitcode_api-1.2.8 → gitcode_api-1.2.10}/tests/test_base_client.py +0 -0
  38. {gitcode_api-1.2.8 → gitcode_api-1.2.10}/tests/test_build_manifest.py +0 -0
  39. {gitcode_api-1.2.8 → gitcode_api-1.2.10}/tests/test_cli.py +0 -0
  40. {gitcode_api-1.2.8 → gitcode_api-1.2.10}/tests/test_client.py +0 -0
  41. {gitcode_api-1.2.8 → gitcode_api-1.2.10}/tests/test_models.py +0 -0
  42. {gitcode_api-1.2.8 → gitcode_api-1.2.10}/tests/test_resources_account.py +0 -0
  43. {gitcode_api-1.2.8 → gitcode_api-1.2.10}/tests/test_resources_collaboration.py +0 -0
  44. {gitcode_api-1.2.8 → gitcode_api-1.2.10}/tests/test_resources_misc.py +0 -0
  45. {gitcode_api-1.2.8 → gitcode_api-1.2.10}/tests/test_resources_repositories.py +0 -0
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gitcode-api
3
- Version: 1.2.8
4
- Summary: Easy to use Python SDK for the GitCode REST API. Providing builtin CLI tool, and optional LLM integration (MCP and OpenAI tool) for agents. Community-maintained.
3
+ Version: 1.2.10
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
7
7
  Project-URL: changelog, https://gitcode-api.readthedocs.io/en/latest/changelog.html
@@ -11,7 +11,7 @@ Project-URL: gitcode, https://gitcode.com/SushiNinja/GitCode-API
11
11
  Project-URL: github, https://github.com/Trenza1ore/GitCode-API
12
12
  Project-URL: homepage, https://linktr.ee/Hugoooo
13
13
  Project-URL: author, https://hugohuang.com
14
- Keywords: gitcode,git,devops,api,sdk,python,httpx,client,mcp,agent,fastmcp,llm,mcp client,mcp server,model context protocol
14
+ Keywords: gitcode,git,devops,api,sdk,python,httpx,client,mcp,agent,fastmcp,llm,openjiuwen,mcp client,mcp server,model context protocol
15
15
  Classifier: Development Status :: 4 - Beta
16
16
  Classifier: Programming Language :: Python
17
17
  Classifier: Programming Language :: Python :: Implementation :: CPython
@@ -38,12 +38,12 @@ Dynamic: license-file
38
38
  # GitCode-API
39
39
 
40
40
  [![PyPI - Version](https://img.shields.io/pypi/v/gitcode-api?link=https%3A%2F%2Fpypi.org%2Fproject%2Fgitcode-api%2F)](https://pypi.org/project/gitcode-api) [![PyPI Downloads](https://static.pepy.tech/personalized-badge/gitcode-api?period=total&units=INTERNATIONAL_SYSTEM&left_color=GRAY&right_color=RED&left_text=downloads)](https://pepy.tech/projects/gitcode-api) [![CodeFactor](https://www.codefactor.io/repository/github/trenza1ore/gitcode-api/badge)](https://www.codefactor.io/repository/github/trenza1ore/gitcode-api)
41
- [![Install in Cursor](https://img.shields.io/badge/Install_in-Cursor-000000?style=flat-square&logoColor=white)](https://cursor.com/en/install-mcp?name=GitCode%20API&config=eyJjb21tYW5kIjoidXZ4IiwiYXJncyI6WyItLWZyb20iLCJnaXRjb2RlLWFwaVttY3BdIiwiZ2l0Y29kZS1hcGkiLCJzZXJ2ZSJdLCJlbnYiOnsiR0lUQ09ERV9BQ0NFU1NfVE9LRU4iOiIke2lucHV0OmdpdGNvZGVfYWNjZXNzX3Rva2VufSJ9LCJpbnB1dHMiOlt7ImlkIjoiZ2l0Y29kZV9hY2Nlc3NfdG9rZW4iLCJ0eXBlIjoicHJvbXB0U3RyaW5nIiwiZGVzY3JpcHRpb24iOiJFbnRlciBHSVRDT0RFX0FDQ0VTU19UT0tFTiIsInBhc3N3b3JkIjp0cnVlfV19) [![Install in VS Code](https://img.shields.io/badge/Install_in-VS_Code-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://vscode.dev/redirect/mcp/install?name=GitCode%20API&config=%7B%22command%22%3A%22uvx%22%2C%22args%22%3A%5B%22--from%22%2C%22gitcode-api%5Bmcp%5D%22%2C%22gitcode-api%22%2C%22serve%22%5D%2C%22env%22%3A%7B%22GITCODE_ACCESS_TOKEN%22%3A%22%24%7Binput%3Agitcode_access_token%7D%22%7D%2C%22inputs%22%3A%5B%7B%22id%22%3A%22gitcode_access_token%22%2C%22type%22%3A%22promptString%22%2C%22description%22%3A%22Enter%20GITCODE_ACCESS_TOKEN%22%2C%22password%22%3Atrue%7D%5D%7D)
41
+ [![Install in Cursor](https://img.shields.io/badge/Install_in-Cursor-000000?logoColor=white)](https://cursor.com/en/install-mcp?name=GitCode%20API&config=eyJjb21tYW5kIjoidXZ4IiwiYXJncyI6WyItLWZyb20iLCJnaXRjb2RlLWFwaVttY3BdIiwiZ2l0Y29kZS1hcGkiLCJzZXJ2ZSJdLCJlbnYiOnsiR0lUQ09ERV9BQ0NFU1NfVE9LRU4iOiIke2lucHV0OmdpdGNvZGVfYWNjZXNzX3Rva2VufSJ9LCJpbnB1dHMiOlt7ImlkIjoiZ2l0Y29kZV9hY2Nlc3NfdG9rZW4iLCJ0eXBlIjoicHJvbXB0U3RyaW5nIiwiZGVzY3JpcHRpb24iOiJFbnRlciBHSVRDT0RFX0FDQ0VTU19UT0tFTiIsInBhc3N3b3JkIjp0cnVlfV19) [![Install in VS Code](https://img.shields.io/badge/Install_in-VS_Code-0098FF?logo=visualstudiocode&logoColor=white)](https://vscode.dev/redirect/mcp/install?name=GitCode%20API&config=%7B%22command%22%3A%22uvx%22%2C%22args%22%3A%5B%22--from%22%2C%22gitcode-api%5Bmcp%5D%22%2C%22gitcode-api%22%2C%22serve%22%5D%2C%22env%22%3A%7B%22GITCODE_ACCESS_TOKEN%22%3A%22%24%7Binput%3Agitcode_access_token%7D%22%7D%2C%22inputs%22%3A%5B%7B%22id%22%3A%22gitcode_access_token%22%2C%22type%22%3A%22promptString%22%2C%22description%22%3A%22Enter%20GITCODE_ACCESS_TOKEN%22%2C%22password%22%3Atrue%7D%5D%7D)
42
42
  [![GitHub Badge](https://img.shields.io/badge/github-repo-blue?logo=github&link=https%3A%2F%2Fgithub.com%2FTrenza1ore%2FGitCode-API)](https://github.com/Trenza1ore/GitCode-API) [![GitCode Badge](https://img.shields.io/badge/gitcode-repo-brown?logo=gitcode&link=https%3A%2F%2Fgitcode.com%2FSushiNinja%2FGitCode-API)](https://gitcode.com/SushiNinja/GitCode-API)
43
43
 
44
44
  [![Docs](https://img.shields.io/badge/%E6%96%87%E6%A1%A3-Docs-cyan?style=for-the-badge&logo=readthedocs&link=https%3A%2F%2Fgitcode-api.readthedocs.io%2Fen%2Flatest%2Findex.html)](https://gitcode-api.readthedocs.io) [![中文README](https://img.shields.io/badge/%E4%B8%AD%E6%96%87-README-brown?style=for-the-badge&logo=googledocs&link=README.zh.md)](README.zh.md)
45
45
 
46
- `gitcode-api` is a community-maintained Python SDK for the GitCode REST API. It provides easy-to-use synchronous and asynchronous clients, repository-scoped helpers, and lightweight response models so you can work with GitCode from Python without hand-writing raw HTTP requests. The `gitcode_api.llm` module adds an OpenAI-style function tool and MCP service so agents can reuse the same resource-oriented API.
46
+ `gitcode-api` is a community-maintained Python SDK for the GitCode REST API. It provides easy-to-use synchronous and asynchronous clients, repository-scoped helpers, and lightweight response models so you can work with GitCode from Python without hand-writing raw HTTP requests. The `gitcode_api.llm` module adds an OpenAI-style function tool, an MCP service, and an [openJiuwen](https://openjiuwen.com) tool integration so agents can reuse the same resource-oriented API.
47
47
 
48
48
  ## Why This Project
49
49
 
@@ -52,8 +52,9 @@ Dynamic: license-file
52
52
  - Resource groups such as `client.repos`, `client.pulls`, and `client.users`.
53
53
  - Repository defaults via `owner=` and `repo=` on the client.
54
54
  - Sphinx docs plus a mirrored GitCode REST API reference in `docs/`.
55
- - Provides MCP server & OpenAI tool for LLM agent usage.
55
+ - Provides MCP server, OpenAI tool, and [openJiuwen](https://openjiuwen.com) tool for LLM agent usage.
56
56
  - Provide MCP service that directly installs to your IDE of choice, such as Cursor and VS Code!
57
+ - Provides an [mcpb bundle](https://www.anthropic.com/engineering/desktop-extensions) you can install directly in the Claude desktop app; download it from [Release](https://github.com/Trenza1ore/GitCode-API/releases/latest).
57
58
 
58
59
  ## Installation
59
60
 
@@ -64,11 +65,11 @@ pip install -U gitcode-api
64
65
  ```
65
66
 
66
67
  Install the MCP server to your AI-powered IDE of choice:
68
+
67
69
  [![Install in Cursor](https://img.shields.io/badge/Install_in-Cursor-000000?style=flat-square&logoColor=white)](https://cursor.com/en/install-mcp?name=GitCode%20API&config=eyJjb21tYW5kIjoidXZ4IiwiYXJncyI6WyItLWZyb20iLCJnaXRjb2RlLWFwaVttY3BdIiwiZ2l0Y29kZS1hcGkiLCJzZXJ2ZSJdLCJlbnYiOnsiR0lUQ09ERV9BQ0NFU1NfVE9LRU4iOiIke2lucHV0OmdpdGNvZGVfYWNjZXNzX3Rva2VufSJ9LCJpbnB1dHMiOlt7ImlkIjoiZ2l0Y29kZV9hY2Nlc3NfdG9rZW4iLCJ0eXBlIjoicHJvbXB0U3RyaW5nIiwiZGVzY3JpcHRpb24iOiJFbnRlciBHSVRDT0RFX0FDQ0VTU19UT0tFTiIsInBhc3N3b3JkIjp0cnVlfV19)
68
70
  [![Install in VS Code](https://img.shields.io/badge/Install_in-VS_Code-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://vscode.dev/redirect/mcp/install?name=GitCode%20API&config=%7B%22command%22%3A%22uvx%22%2C%22args%22%3A%5B%22--from%22%2C%22gitcode-api%5Bmcp%5D%22%2C%22gitcode-api%22%2C%22serve%22%5D%2C%22env%22%3A%7B%22GITCODE_ACCESS_TOKEN%22%3A%22%24%7Binput%3Agitcode_access_token%7D%22%7D%2C%22inputs%22%3A%5B%7B%22id%22%3A%22gitcode_access_token%22%2C%22type%22%3A%22promptString%22%2C%22description%22%3A%22Enter%20GITCODE_ACCESS_TOKEN%22%2C%22password%22%3Atrue%7D%5D%7D)
69
71
  [![Install in VS Code Insiders](https://img.shields.io/badge/Install_in-VS_Code_Insiders-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=GitCode%20API&config=%7B%22command%22%3A%22uvx%22%2C%22args%22%3A%5B%22--from%22%2C%22gitcode-api%5Bmcp%5D%22%2C%22gitcode-api%22%2C%22serve%22%5D%2C%22env%22%3A%7B%22GITCODE_ACCESS_TOKEN%22%3A%22%24%7Binput%3Agitcode_access_token%7D%22%7D%2C%22inputs%22%3A%5B%7B%22id%22%3A%22gitcode_access_token%22%2C%22type%22%3A%22promptString%22%2C%22description%22%3A%22Enter%20GITCODE_ACCESS_TOKEN%22%2C%22password%22%3Atrue%7D%5D%7D&quality=insiders)
70
72
  [![Install in Visual Studio](https://img.shields.io/badge/Install_in-Visual_Studio-C16FDE?style=flat-square&logo=visualstudio&logoColor=white)](https://vs-open.link/mcp-install?%7B%22command%22%3A%22uvx%22%2C%22args%22%3A%5B%22--from%22%2C%22gitcode-api%5Bmcp%5D%22%2C%22gitcode-api%22%2C%22serve%22%5D%2C%22env%22%3A%7B%22GITCODE_ACCESS_TOKEN%22%3A%22%24%7Binput%3Agitcode_access_token%7D%22%7D%2C%22inputs%22%3A%5B%7B%22id%22%3A%22gitcode_access_token%22%2C%22type%22%3A%22promptString%22%2C%22description%22%3A%22Enter%20GITCODE_ACCESS_TOKEN%22%2C%22password%22%3Atrue%7D%5D%7D)
71
- [![Install in Goose](https://block.github.io/goose/img/extension-install-dark.svg)](https://block.github.io/goose/extension?cmd=uvx&arg=--from%2520gitcode-api%5Bmcp%5D%2520gitcode-api%2520serve&id=GitCode%20API&name=GitCode%20API&description=MCP%20Server%20for%20GitCode%20API)
72
73
  [![Add MCP Server GitCode API to LM Studio](https://files.lmstudio.ai/deeplink/mcp-install-light.svg)](https://lmstudio.ai/install-mcp?name=GitCode%20API&config=eyJjb21tYW5kIjoidXZ4IiwiYXJncyI6WyItLWZyb20iLCJnaXRjb2RlLWFwaVttY3BdIiwiZ2l0Y29kZS1hcGkiLCJzZXJ2ZSJdLCJlbnYiOnsiR0lUQ09ERV9BQ0NFU1NfVE9LRU4iOiIke2lucHV0OmdpdGNvZGVfYWNjZXNzX3Rva2VufSJ9LCJpbnB1dHMiOlt7ImlkIjoiZ2l0Y29kZV9hY2Nlc3NfdG9rZW4iLCJ0eXBlIjoicHJvbXB0U3RyaW5nIiwiZGVzY3JpcHRpb24iOiJFbnRlciBHSVRDT0RFX0FDQ0VTU19UT0tFTiIsInBhc3N3b3JkIjp0cnVlfV19)
73
74
 
74
75
  For detailed setup (including installing to services like Claude Code / Codex): see [install_mcp_server.md](install_mcp_server.md).
@@ -228,7 +229,7 @@ Both `GitCode` and `AsyncGitCode` expose:
228
229
 
229
230
  Every resource group inherits a cached `methods` property from the shared resource base: a `tuple` of public callable names in stable SDK order (underscore-segment sort key, not plain A–Z on the full identifier). Private names and the introspection helpers `methods` and `method_signature` are omitted. For example, `client.pulls.methods` helps with discovery or tooling without reading the full manual list. For one method’s parameters and return type, call `client.pulls.method_signature("list_issues")` (a cached string from `inspect.signature`, with `gitcode_api._models.` stripped from annotations).
230
231
 
231
- ## LLM tools and MCP
232
+ ## LLM tools, MCP, and openJiuwen
232
233
 
233
234
  The `gitcode_api.llm` module exposes a single logical tool, **`gitcode_api_tool`**, that routes calls to sync or async SDK resources. Model-facing parameters match the JSON schema used by OpenAI-style function tools:
234
235
 
@@ -239,11 +240,11 @@ The `gitcode_api.llm` module exposes a single logical tool, **`gitcode_api_tool`
239
240
  | `params` | Keyword arguments for the method as a JSON object; omitted or `null` is treated as `{}`. |
240
241
  | `help` | When `true`, returns formatted help (available methods or a target signature) instead of performing a normal API call where applicable. |
241
242
 
242
- 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.
243
244
 
244
245
  ### OpenAI tool (`GitCodeOpenAITool`)
245
246
 
246
- 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.
247
248
 
248
249
  ```python
249
250
  from gitcode_api.llm import GitCodeOpenAITool
@@ -264,33 +265,43 @@ and handle tool calls directly:
264
265
 
265
266
  ```python
266
267
  import json
267
- from openai import OpenAI
268
- from gitcode_api.llm import GitCodeOpenAITool
268
+ import os
269
+ from typing import Dict, List
269
270
 
270
- tools = {
271
- "gitcode_api_tool": GitCodeOpenAITool(owner="SushiNinja", repo="GitCode-API"),
272
- }
273
- client = OpenAI(
274
- api_key="your-openai-compatible-api-key",
275
- base_url="https://your-openai-compatible-base-url/v1",
276
- )
271
+ from openai import OpenAI
277
272
 
278
- response = client.chat.completions.create(
279
- model="gpt-4.1-mini",
280
- messages=[{"role": "user", "content": "List the last 5 commits."}],
281
- tools=[tools["gitcode_api_tool"].tool],
282
- )
273
+ from gitcode_api.llm import GitCodeOpenAITool
283
274
 
284
- for tool_call in response.choices[0].message.tool_calls:
285
- selected_tool = tools[tool_call.function.name]
286
- print(f"Calling tool {tool_call.function.name}({tool_call.function.arguments}):")
287
- print("---result---")
288
- print(selected_tool(**json.loads(tool_call.function.arguments)))
289
- 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
290
303
  ```
291
304
 
292
- 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).
293
-
294
305
  ### MCP server and MCP tool (FastMCP)
295
306
 
296
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):
@@ -315,6 +326,24 @@ The same server is available from the CLI as `gitcode-api serve` (see the [CLI](
315
326
 
316
327
  To share auth or clients across tools, build `GitCodeLLMTool` once (`from gitcode_api.llm._tool import GitCodeLLMTool`) and pass it as `tool=` into `GitCodeMCP`, `create_mcp_server`, `register_mcp_gitcode_api_tool`, or `create_mcp_gitcode_api_tool`.
317
328
 
329
+ ### openJiuwen (`LocalFunction`)
330
+
331
+ [openJiuwen](https://openjiuwen.com) is an open agent platform. With the separate `openjiuwen` package installed (**Python 3.11+**), `create_openjiuwen_gitcode_api_tool` returns an openJiuwen `LocalFunction` that uses the same `op_type` / `action` / `params` / `help` arguments as the OpenAI adapter. Invocation is async-only (`await jiuwen_tool.invoke({...})`).
332
+
333
+ ```bash
334
+ pip install openjiuwen
335
+ ```
336
+
337
+ ```python
338
+ from gitcode_api.llm import create_openjiuwen_gitcode_api_tool
339
+
340
+ jiuwen_tool = create_openjiuwen_gitcode_api_tool(owner="SushiNinja", repo="GitCode-API")
341
+ # jiuwen_tool.card — name, description, input_params
342
+ # await jiuwen_tool.invoke({"op_type": "repos", "action": "get", "params": {}})
343
+ ```
344
+
345
+ Optional `name=` and `description=` override the default tool card. Constructor options otherwise mirror `GitCode` / `AsyncGitCode` (`client=`, `async_client=`, `api_key=`, `owner=`, `repo=`, `base_url=`, `timeout=`, `decrypt=`).
346
+
318
347
  **Claude Desktop (MCPB):** published GitHub Releases include a `gitcode-<version>.mcpb` bundle for one-click installation as a Claude Desktop extension; see Anthropic’s guide, [Build a desktop extension with MCPB](https://claude.com/docs/connectors/building/mcpb). From a checkout you can run `make mcpb` (requires the [`@anthropic-ai/mcpb`](https://www.npmjs.com/package/@anthropic-ai/mcpb) CLI on your `PATH`).
319
348
 
320
349
  ## Examples
@@ -378,7 +407,7 @@ with GitCode(
378
407
 
379
408
  Use `httpx.AsyncClient(verify=...)` with `AsyncGitCode` for async code.
380
409
 
381
- The OpenAI tool (`GitCodeOpenAITool`) and MCP helpers accept the same `client=` / `async_client=` arguments (or a shared `GitCodeLLMTool` via `tool=` with those clients set). Build `GitCode` / `AsyncGitCode` with your custom `http_client` once and pass it through so LLM tool calls reuse the same TLS settings.
410
+ The OpenAI tool (`GitCodeOpenAITool`), MCP helpers, and `create_openjiuwen_gitcode_api_tool` accept the same `client=` / `async_client=` arguments (OpenAI and MCP also accept a shared `GitCodeLLMTool` via `tool=`). Build `GitCode` / `AsyncGitCode` with your custom `http_client` once and pass it through so LLM tool calls reuse the same TLS settings.
382
411
 
383
412
  ## Project Status
384
413
 
@@ -1,12 +1,12 @@
1
1
  # GitCode-API
2
2
 
3
3
  [![PyPI - Version](https://img.shields.io/pypi/v/gitcode-api?link=https%3A%2F%2Fpypi.org%2Fproject%2Fgitcode-api%2F)](https://pypi.org/project/gitcode-api) [![PyPI Downloads](https://static.pepy.tech/personalized-badge/gitcode-api?period=total&units=INTERNATIONAL_SYSTEM&left_color=GRAY&right_color=RED&left_text=downloads)](https://pepy.tech/projects/gitcode-api) [![CodeFactor](https://www.codefactor.io/repository/github/trenza1ore/gitcode-api/badge)](https://www.codefactor.io/repository/github/trenza1ore/gitcode-api)
4
- [![Install in Cursor](https://img.shields.io/badge/Install_in-Cursor-000000?style=flat-square&logoColor=white)](https://cursor.com/en/install-mcp?name=GitCode%20API&config=eyJjb21tYW5kIjoidXZ4IiwiYXJncyI6WyItLWZyb20iLCJnaXRjb2RlLWFwaVttY3BdIiwiZ2l0Y29kZS1hcGkiLCJzZXJ2ZSJdLCJlbnYiOnsiR0lUQ09ERV9BQ0NFU1NfVE9LRU4iOiIke2lucHV0OmdpdGNvZGVfYWNjZXNzX3Rva2VufSJ9LCJpbnB1dHMiOlt7ImlkIjoiZ2l0Y29kZV9hY2Nlc3NfdG9rZW4iLCJ0eXBlIjoicHJvbXB0U3RyaW5nIiwiZGVzY3JpcHRpb24iOiJFbnRlciBHSVRDT0RFX0FDQ0VTU19UT0tFTiIsInBhc3N3b3JkIjp0cnVlfV19) [![Install in VS Code](https://img.shields.io/badge/Install_in-VS_Code-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://vscode.dev/redirect/mcp/install?name=GitCode%20API&config=%7B%22command%22%3A%22uvx%22%2C%22args%22%3A%5B%22--from%22%2C%22gitcode-api%5Bmcp%5D%22%2C%22gitcode-api%22%2C%22serve%22%5D%2C%22env%22%3A%7B%22GITCODE_ACCESS_TOKEN%22%3A%22%24%7Binput%3Agitcode_access_token%7D%22%7D%2C%22inputs%22%3A%5B%7B%22id%22%3A%22gitcode_access_token%22%2C%22type%22%3A%22promptString%22%2C%22description%22%3A%22Enter%20GITCODE_ACCESS_TOKEN%22%2C%22password%22%3Atrue%7D%5D%7D)
4
+ [![Install in Cursor](https://img.shields.io/badge/Install_in-Cursor-000000?logoColor=white)](https://cursor.com/en/install-mcp?name=GitCode%20API&config=eyJjb21tYW5kIjoidXZ4IiwiYXJncyI6WyItLWZyb20iLCJnaXRjb2RlLWFwaVttY3BdIiwiZ2l0Y29kZS1hcGkiLCJzZXJ2ZSJdLCJlbnYiOnsiR0lUQ09ERV9BQ0NFU1NfVE9LRU4iOiIke2lucHV0OmdpdGNvZGVfYWNjZXNzX3Rva2VufSJ9LCJpbnB1dHMiOlt7ImlkIjoiZ2l0Y29kZV9hY2Nlc3NfdG9rZW4iLCJ0eXBlIjoicHJvbXB0U3RyaW5nIiwiZGVzY3JpcHRpb24iOiJFbnRlciBHSVRDT0RFX0FDQ0VTU19UT0tFTiIsInBhc3N3b3JkIjp0cnVlfV19) [![Install in VS Code](https://img.shields.io/badge/Install_in-VS_Code-0098FF?logo=visualstudiocode&logoColor=white)](https://vscode.dev/redirect/mcp/install?name=GitCode%20API&config=%7B%22command%22%3A%22uvx%22%2C%22args%22%3A%5B%22--from%22%2C%22gitcode-api%5Bmcp%5D%22%2C%22gitcode-api%22%2C%22serve%22%5D%2C%22env%22%3A%7B%22GITCODE_ACCESS_TOKEN%22%3A%22%24%7Binput%3Agitcode_access_token%7D%22%7D%2C%22inputs%22%3A%5B%7B%22id%22%3A%22gitcode_access_token%22%2C%22type%22%3A%22promptString%22%2C%22description%22%3A%22Enter%20GITCODE_ACCESS_TOKEN%22%2C%22password%22%3Atrue%7D%5D%7D)
5
5
  [![GitHub Badge](https://img.shields.io/badge/github-repo-blue?logo=github&link=https%3A%2F%2Fgithub.com%2FTrenza1ore%2FGitCode-API)](https://github.com/Trenza1ore/GitCode-API) [![GitCode Badge](https://img.shields.io/badge/gitcode-repo-brown?logo=gitcode&link=https%3A%2F%2Fgitcode.com%2FSushiNinja%2FGitCode-API)](https://gitcode.com/SushiNinja/GitCode-API)
6
6
 
7
7
  [![Docs](https://img.shields.io/badge/%E6%96%87%E6%A1%A3-Docs-cyan?style=for-the-badge&logo=readthedocs&link=https%3A%2F%2Fgitcode-api.readthedocs.io%2Fen%2Flatest%2Findex.html)](https://gitcode-api.readthedocs.io) [![中文README](https://img.shields.io/badge/%E4%B8%AD%E6%96%87-README-brown?style=for-the-badge&logo=googledocs&link=README.zh.md)](README.zh.md)
8
8
 
9
- `gitcode-api` is a community-maintained Python SDK for the GitCode REST API. It provides easy-to-use synchronous and asynchronous clients, repository-scoped helpers, and lightweight response models so you can work with GitCode from Python without hand-writing raw HTTP requests. The `gitcode_api.llm` module adds an OpenAI-style function tool and MCP service so agents can reuse the same resource-oriented API.
9
+ `gitcode-api` is a community-maintained Python SDK for the GitCode REST API. It provides easy-to-use synchronous and asynchronous clients, repository-scoped helpers, and lightweight response models so you can work with GitCode from Python without hand-writing raw HTTP requests. The `gitcode_api.llm` module adds an OpenAI-style function tool, an MCP service, and an [openJiuwen](https://openjiuwen.com) tool integration so agents can reuse the same resource-oriented API.
10
10
 
11
11
  ## Why This Project
12
12
 
@@ -15,8 +15,9 @@
15
15
  - Resource groups such as `client.repos`, `client.pulls`, and `client.users`.
16
16
  - Repository defaults via `owner=` and `repo=` on the client.
17
17
  - Sphinx docs plus a mirrored GitCode REST API reference in `docs/`.
18
- - Provides MCP server & OpenAI tool for LLM agent usage.
18
+ - Provides MCP server, OpenAI tool, and [openJiuwen](https://openjiuwen.com) tool for LLM agent usage.
19
19
  - Provide MCP service that directly installs to your IDE of choice, such as Cursor and VS Code!
20
+ - Provides an [mcpb bundle](https://www.anthropic.com/engineering/desktop-extensions) you can install directly in the Claude desktop app; download it from [Release](https://github.com/Trenza1ore/GitCode-API/releases/latest).
20
21
 
21
22
  ## Installation
22
23
 
@@ -27,11 +28,11 @@ pip install -U gitcode-api
27
28
  ```
28
29
 
29
30
  Install the MCP server to your AI-powered IDE of choice:
31
+
30
32
  [![Install in Cursor](https://img.shields.io/badge/Install_in-Cursor-000000?style=flat-square&logoColor=white)](https://cursor.com/en/install-mcp?name=GitCode%20API&config=eyJjb21tYW5kIjoidXZ4IiwiYXJncyI6WyItLWZyb20iLCJnaXRjb2RlLWFwaVttY3BdIiwiZ2l0Y29kZS1hcGkiLCJzZXJ2ZSJdLCJlbnYiOnsiR0lUQ09ERV9BQ0NFU1NfVE9LRU4iOiIke2lucHV0OmdpdGNvZGVfYWNjZXNzX3Rva2VufSJ9LCJpbnB1dHMiOlt7ImlkIjoiZ2l0Y29kZV9hY2Nlc3NfdG9rZW4iLCJ0eXBlIjoicHJvbXB0U3RyaW5nIiwiZGVzY3JpcHRpb24iOiJFbnRlciBHSVRDT0RFX0FDQ0VTU19UT0tFTiIsInBhc3N3b3JkIjp0cnVlfV19)
31
33
  [![Install in VS Code](https://img.shields.io/badge/Install_in-VS_Code-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://vscode.dev/redirect/mcp/install?name=GitCode%20API&config=%7B%22command%22%3A%22uvx%22%2C%22args%22%3A%5B%22--from%22%2C%22gitcode-api%5Bmcp%5D%22%2C%22gitcode-api%22%2C%22serve%22%5D%2C%22env%22%3A%7B%22GITCODE_ACCESS_TOKEN%22%3A%22%24%7Binput%3Agitcode_access_token%7D%22%7D%2C%22inputs%22%3A%5B%7B%22id%22%3A%22gitcode_access_token%22%2C%22type%22%3A%22promptString%22%2C%22description%22%3A%22Enter%20GITCODE_ACCESS_TOKEN%22%2C%22password%22%3Atrue%7D%5D%7D)
32
34
  [![Install in VS Code Insiders](https://img.shields.io/badge/Install_in-VS_Code_Insiders-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=GitCode%20API&config=%7B%22command%22%3A%22uvx%22%2C%22args%22%3A%5B%22--from%22%2C%22gitcode-api%5Bmcp%5D%22%2C%22gitcode-api%22%2C%22serve%22%5D%2C%22env%22%3A%7B%22GITCODE_ACCESS_TOKEN%22%3A%22%24%7Binput%3Agitcode_access_token%7D%22%7D%2C%22inputs%22%3A%5B%7B%22id%22%3A%22gitcode_access_token%22%2C%22type%22%3A%22promptString%22%2C%22description%22%3A%22Enter%20GITCODE_ACCESS_TOKEN%22%2C%22password%22%3Atrue%7D%5D%7D&quality=insiders)
33
35
  [![Install in Visual Studio](https://img.shields.io/badge/Install_in-Visual_Studio-C16FDE?style=flat-square&logo=visualstudio&logoColor=white)](https://vs-open.link/mcp-install?%7B%22command%22%3A%22uvx%22%2C%22args%22%3A%5B%22--from%22%2C%22gitcode-api%5Bmcp%5D%22%2C%22gitcode-api%22%2C%22serve%22%5D%2C%22env%22%3A%7B%22GITCODE_ACCESS_TOKEN%22%3A%22%24%7Binput%3Agitcode_access_token%7D%22%7D%2C%22inputs%22%3A%5B%7B%22id%22%3A%22gitcode_access_token%22%2C%22type%22%3A%22promptString%22%2C%22description%22%3A%22Enter%20GITCODE_ACCESS_TOKEN%22%2C%22password%22%3Atrue%7D%5D%7D)
34
- [![Install in Goose](https://block.github.io/goose/img/extension-install-dark.svg)](https://block.github.io/goose/extension?cmd=uvx&arg=--from%2520gitcode-api%5Bmcp%5D%2520gitcode-api%2520serve&id=GitCode%20API&name=GitCode%20API&description=MCP%20Server%20for%20GitCode%20API)
35
36
  [![Add MCP Server GitCode API to LM Studio](https://files.lmstudio.ai/deeplink/mcp-install-light.svg)](https://lmstudio.ai/install-mcp?name=GitCode%20API&config=eyJjb21tYW5kIjoidXZ4IiwiYXJncyI6WyItLWZyb20iLCJnaXRjb2RlLWFwaVttY3BdIiwiZ2l0Y29kZS1hcGkiLCJzZXJ2ZSJdLCJlbnYiOnsiR0lUQ09ERV9BQ0NFU1NfVE9LRU4iOiIke2lucHV0OmdpdGNvZGVfYWNjZXNzX3Rva2VufSJ9LCJpbnB1dHMiOlt7ImlkIjoiZ2l0Y29kZV9hY2Nlc3NfdG9rZW4iLCJ0eXBlIjoicHJvbXB0U3RyaW5nIiwiZGVzY3JpcHRpb24iOiJFbnRlciBHSVRDT0RFX0FDQ0VTU19UT0tFTiIsInBhc3N3b3JkIjp0cnVlfV19)
36
37
 
37
38
  For detailed setup (including installing to services like Claude Code / Codex): see [install_mcp_server.md](install_mcp_server.md).
@@ -191,7 +192,7 @@ Both `GitCode` and `AsyncGitCode` expose:
191
192
 
192
193
  Every resource group inherits a cached `methods` property from the shared resource base: a `tuple` of public callable names in stable SDK order (underscore-segment sort key, not plain A–Z on the full identifier). Private names and the introspection helpers `methods` and `method_signature` are omitted. For example, `client.pulls.methods` helps with discovery or tooling without reading the full manual list. For one method’s parameters and return type, call `client.pulls.method_signature("list_issues")` (a cached string from `inspect.signature`, with `gitcode_api._models.` stripped from annotations).
193
194
 
194
- ## LLM tools and MCP
195
+ ## LLM tools, MCP, and openJiuwen
195
196
 
196
197
  The `gitcode_api.llm` module exposes a single logical tool, **`gitcode_api_tool`**, that routes calls to sync or async SDK resources. Model-facing parameters match the JSON schema used by OpenAI-style function tools:
197
198
 
@@ -202,11 +203,11 @@ The `gitcode_api.llm` module exposes a single logical tool, **`gitcode_api_tool`
202
203
  | `params` | Keyword arguments for the method as a JSON object; omitted or `null` is treated as `{}`. |
203
204
  | `help` | When `true`, returns formatted help (available methods or a target signature) instead of performing a normal API call where applicable. |
204
205
 
205
- 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.
206
207
 
207
208
  ### OpenAI tool (`GitCodeOpenAITool`)
208
209
 
209
- 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.
210
211
 
211
212
  ```python
212
213
  from gitcode_api.llm import GitCodeOpenAITool
@@ -227,33 +228,43 @@ and handle tool calls directly:
227
228
 
228
229
  ```python
229
230
  import json
230
- from openai import OpenAI
231
- from gitcode_api.llm import GitCodeOpenAITool
231
+ import os
232
+ from typing import Dict, List
232
233
 
233
- tools = {
234
- "gitcode_api_tool": GitCodeOpenAITool(owner="SushiNinja", repo="GitCode-API"),
235
- }
236
- client = OpenAI(
237
- api_key="your-openai-compatible-api-key",
238
- base_url="https://your-openai-compatible-base-url/v1",
239
- )
234
+ from openai import OpenAI
240
235
 
241
- response = client.chat.completions.create(
242
- model="gpt-4.1-mini",
243
- messages=[{"role": "user", "content": "List the last 5 commits."}],
244
- tools=[tools["gitcode_api_tool"].tool],
245
- )
236
+ from gitcode_api.llm import GitCodeOpenAITool
246
237
 
247
- for tool_call in response.choices[0].message.tool_calls:
248
- selected_tool = tools[tool_call.function.name]
249
- print(f"Calling tool {tool_call.function.name}({tool_call.function.arguments}):")
250
- print("---result---")
251
- print(selected_tool(**json.loads(tool_call.function.arguments)))
252
- 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
253
266
  ```
254
267
 
255
- 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).
256
-
257
268
  ### MCP server and MCP tool (FastMCP)
258
269
 
259
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):
@@ -278,6 +289,24 @@ The same server is available from the CLI as `gitcode-api serve` (see the [CLI](
278
289
 
279
290
  To share auth or clients across tools, build `GitCodeLLMTool` once (`from gitcode_api.llm._tool import GitCodeLLMTool`) and pass it as `tool=` into `GitCodeMCP`, `create_mcp_server`, `register_mcp_gitcode_api_tool`, or `create_mcp_gitcode_api_tool`.
280
291
 
292
+ ### openJiuwen (`LocalFunction`)
293
+
294
+ [openJiuwen](https://openjiuwen.com) is an open agent platform. With the separate `openjiuwen` package installed (**Python 3.11+**), `create_openjiuwen_gitcode_api_tool` returns an openJiuwen `LocalFunction` that uses the same `op_type` / `action` / `params` / `help` arguments as the OpenAI adapter. Invocation is async-only (`await jiuwen_tool.invoke({...})`).
295
+
296
+ ```bash
297
+ pip install openjiuwen
298
+ ```
299
+
300
+ ```python
301
+ from gitcode_api.llm import create_openjiuwen_gitcode_api_tool
302
+
303
+ jiuwen_tool = create_openjiuwen_gitcode_api_tool(owner="SushiNinja", repo="GitCode-API")
304
+ # jiuwen_tool.card — name, description, input_params
305
+ # await jiuwen_tool.invoke({"op_type": "repos", "action": "get", "params": {}})
306
+ ```
307
+
308
+ Optional `name=` and `description=` override the default tool card. Constructor options otherwise mirror `GitCode` / `AsyncGitCode` (`client=`, `async_client=`, `api_key=`, `owner=`, `repo=`, `base_url=`, `timeout=`, `decrypt=`).
309
+
281
310
  **Claude Desktop (MCPB):** published GitHub Releases include a `gitcode-<version>.mcpb` bundle for one-click installation as a Claude Desktop extension; see Anthropic’s guide, [Build a desktop extension with MCPB](https://claude.com/docs/connectors/building/mcpb). From a checkout you can run `make mcpb` (requires the [`@anthropic-ai/mcpb`](https://www.npmjs.com/package/@anthropic-ai/mcpb) CLI on your `PATH`).
282
311
 
283
312
  ## Examples
@@ -341,7 +370,7 @@ with GitCode(
341
370
 
342
371
  Use `httpx.AsyncClient(verify=...)` with `AsyncGitCode` for async code.
343
372
 
344
- The OpenAI tool (`GitCodeOpenAITool`) and MCP helpers accept the same `client=` / `async_client=` arguments (or a shared `GitCodeLLMTool` via `tool=` with those clients set). Build `GitCode` / `AsyncGitCode` with your custom `http_client` once and pass it through so LLM tool calls reuse the same TLS settings.
373
+ The OpenAI tool (`GitCodeOpenAITool`), MCP helpers, and `create_openjiuwen_gitcode_api_tool` accept the same `client=` / `async_client=` arguments (OpenAI and MCP also accept a shared `GitCodeLLMTool` via `tool=`). Build `GitCode` / `AsyncGitCode` with your custom `http_client` once and pass it through so LLM tool calls reuse the same TLS settings.
345
374
 
346
375
  ## Project Status
347
376
 
@@ -4,6 +4,7 @@ from importlib import import_module
4
4
  from typing import TYPE_CHECKING, Any, Dict
5
5
 
6
6
  if TYPE_CHECKING:
7
+ from .jiuwen import create_openjiuwen_gitcode_api_tool
7
8
  from .mcp import (
8
9
  GitCodeMCP,
9
10
  create_mcp_gitcode_api_tool,
@@ -21,6 +22,7 @@ _IMPORT_MAP = {
21
22
  "register_mcp_gitcode_api_tool": ".mcp",
22
23
  "register_mcp_help_resources": ".mcp",
23
24
  "GitCodeOpenAITool": ".openai",
25
+ "create_openjiuwen_gitcode_api_tool": ".jiuwen",
24
26
  }
25
27
 
26
28
  _IMPORT_CACHE: Dict[str, Any] = {}
@@ -54,4 +56,5 @@ __all__ = [
54
56
  "create_mcp_server",
55
57
  "register_mcp_gitcode_api_tool",
56
58
  "register_mcp_help_resources",
59
+ "create_openjiuwen_gitcode_api_tool",
57
60
  ]
@@ -0,0 +1,98 @@
1
+ """openJiuwen ``LocalFunction`` adapter for the GitCode LLM tool."""
2
+
3
+ from importlib import import_module
4
+ from typing import TYPE_CHECKING, Any, Callable, Dict, Optional
5
+
6
+ from gitcode_api import AsyncGitCode, GitCode
7
+ from gitcode_api._base_client import DEFAULT_BASE_URL
8
+
9
+ from ._tool import TOOL_DESCRIPTION, TOOL_NAME, TOOL_PARAMETERS, GitCodeLLMTool
10
+
11
+ if TYPE_CHECKING:
12
+ from openjiuwen.core.foundation.tool import LocalFunction
13
+
14
+
15
+ def _missing_openjiuwen_error() -> ImportError:
16
+ return ImportError(
17
+ "The openJiuwen tool support requires the optional dependency: pip install openjiuwen. "
18
+ "Note: Python 3.11+ is required for openjiuwen."
19
+ )
20
+
21
+
22
+ def _openjiuwen_tool_decorator() -> Callable[..., Any]:
23
+ try:
24
+ mod = import_module("openjiuwen.core.foundation.tool")
25
+ except ImportError as exc:
26
+ raise _missing_openjiuwen_error() from exc
27
+ return getattr(mod, "tool") # type: ignore[no-any-return]
28
+
29
+
30
+ class _GitCodeJiuwenTool(GitCodeLLMTool):
31
+ """Build an openJiuwen ``LocalFunction`` bound to :class:`GitCodeLLMTool` (async invoke only)."""
32
+
33
+ def __init__(self, *, name: Optional[str] = None, description: Optional[str] = None, **kwargs) -> None:
34
+ super().__init__(**kwargs)
35
+ tool_name = name if name is not None else TOOL_NAME
36
+ tool_description = description if description is not None else TOOL_DESCRIPTION
37
+ oj_tool = _openjiuwen_tool_decorator()
38
+
39
+ async def _async_impl(
40
+ op_type: str,
41
+ action: str = "",
42
+ params: Optional[Dict[str, Any]] = None,
43
+ help: bool = False,
44
+ ) -> Any:
45
+ return await self.__async_call__(op_type=op_type, action=action, params=params, help=help)
46
+
47
+ self.local_function = oj_tool(
48
+ _async_impl,
49
+ name=tool_name,
50
+ description=tool_description,
51
+ input_params=TOOL_PARAMETERS,
52
+ auto_extract=False,
53
+ )
54
+
55
+
56
+ def create_openjiuwen_gitcode_api_tool(
57
+ name: Optional[str] = None,
58
+ description: Optional[str] = None,
59
+ *,
60
+ client: Optional[GitCode] = None,
61
+ async_client: Optional[AsyncGitCode] = None,
62
+ api_key: Optional[str] = None,
63
+ owner: Optional[str] = None,
64
+ repo: Optional[str] = None,
65
+ base_url: str = DEFAULT_BASE_URL,
66
+ timeout: Optional[float] = None,
67
+ decrypt: Optional[Callable[..., Any]] = None,
68
+ ) -> "LocalFunction":
69
+ """Create an openJiuwen ``LocalFunction`` for the GitCode API tool.
70
+
71
+ :param name: Tool name on the ``LocalFunction`` card; defaults to ``gitcode_api_tool``.
72
+ :param description: Tool description on the card; defaults to the shared GitCode tool description.
73
+ :param client: Optional synchronous GitCode client.
74
+ :param async_client: Optional asynchronous GitCode client.
75
+ :param api_key: Personal access token when clients are not supplied.
76
+ :param owner: Default repository owner for generated clients.
77
+ :param repo: Default repository name for generated clients.
78
+ :param base_url: Base URL for generated clients.
79
+ :param timeout: Request timeout for generated clients.
80
+ :param decrypt: Optional decryption function for encrypted access tokens.
81
+ :returns: openJiuwen ``LocalFunction`` with the standard parameter schema.
82
+ """
83
+ adapter = _GitCodeJiuwenTool(
84
+ client=client,
85
+ async_client=async_client,
86
+ api_key=api_key,
87
+ owner=owner,
88
+ repo=repo,
89
+ base_url=base_url,
90
+ timeout=timeout,
91
+ decrypt=decrypt,
92
+ name=name,
93
+ description=description,
94
+ )
95
+ return adapter.local_function
96
+
97
+
98
+ __all__ = ["create_openjiuwen_gitcode_api_tool"]
@@ -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,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gitcode-api
3
- Version: 1.2.8
4
- Summary: Easy to use Python SDK for the GitCode REST API. Providing builtin CLI tool, and optional LLM integration (MCP and OpenAI tool) for agents. Community-maintained.
3
+ Version: 1.2.10
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
7
7
  Project-URL: changelog, https://gitcode-api.readthedocs.io/en/latest/changelog.html
@@ -11,7 +11,7 @@ Project-URL: gitcode, https://gitcode.com/SushiNinja/GitCode-API
11
11
  Project-URL: github, https://github.com/Trenza1ore/GitCode-API
12
12
  Project-URL: homepage, https://linktr.ee/Hugoooo
13
13
  Project-URL: author, https://hugohuang.com
14
- Keywords: gitcode,git,devops,api,sdk,python,httpx,client,mcp,agent,fastmcp,llm,mcp client,mcp server,model context protocol
14
+ Keywords: gitcode,git,devops,api,sdk,python,httpx,client,mcp,agent,fastmcp,llm,openjiuwen,mcp client,mcp server,model context protocol
15
15
  Classifier: Development Status :: 4 - Beta
16
16
  Classifier: Programming Language :: Python
17
17
  Classifier: Programming Language :: Python :: Implementation :: CPython
@@ -38,12 +38,12 @@ Dynamic: license-file
38
38
  # GitCode-API
39
39
 
40
40
  [![PyPI - Version](https://img.shields.io/pypi/v/gitcode-api?link=https%3A%2F%2Fpypi.org%2Fproject%2Fgitcode-api%2F)](https://pypi.org/project/gitcode-api) [![PyPI Downloads](https://static.pepy.tech/personalized-badge/gitcode-api?period=total&units=INTERNATIONAL_SYSTEM&left_color=GRAY&right_color=RED&left_text=downloads)](https://pepy.tech/projects/gitcode-api) [![CodeFactor](https://www.codefactor.io/repository/github/trenza1ore/gitcode-api/badge)](https://www.codefactor.io/repository/github/trenza1ore/gitcode-api)
41
- [![Install in Cursor](https://img.shields.io/badge/Install_in-Cursor-000000?style=flat-square&logoColor=white)](https://cursor.com/en/install-mcp?name=GitCode%20API&config=eyJjb21tYW5kIjoidXZ4IiwiYXJncyI6WyItLWZyb20iLCJnaXRjb2RlLWFwaVttY3BdIiwiZ2l0Y29kZS1hcGkiLCJzZXJ2ZSJdLCJlbnYiOnsiR0lUQ09ERV9BQ0NFU1NfVE9LRU4iOiIke2lucHV0OmdpdGNvZGVfYWNjZXNzX3Rva2VufSJ9LCJpbnB1dHMiOlt7ImlkIjoiZ2l0Y29kZV9hY2Nlc3NfdG9rZW4iLCJ0eXBlIjoicHJvbXB0U3RyaW5nIiwiZGVzY3JpcHRpb24iOiJFbnRlciBHSVRDT0RFX0FDQ0VTU19UT0tFTiIsInBhc3N3b3JkIjp0cnVlfV19) [![Install in VS Code](https://img.shields.io/badge/Install_in-VS_Code-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://vscode.dev/redirect/mcp/install?name=GitCode%20API&config=%7B%22command%22%3A%22uvx%22%2C%22args%22%3A%5B%22--from%22%2C%22gitcode-api%5Bmcp%5D%22%2C%22gitcode-api%22%2C%22serve%22%5D%2C%22env%22%3A%7B%22GITCODE_ACCESS_TOKEN%22%3A%22%24%7Binput%3Agitcode_access_token%7D%22%7D%2C%22inputs%22%3A%5B%7B%22id%22%3A%22gitcode_access_token%22%2C%22type%22%3A%22promptString%22%2C%22description%22%3A%22Enter%20GITCODE_ACCESS_TOKEN%22%2C%22password%22%3Atrue%7D%5D%7D)
41
+ [![Install in Cursor](https://img.shields.io/badge/Install_in-Cursor-000000?logoColor=white)](https://cursor.com/en/install-mcp?name=GitCode%20API&config=eyJjb21tYW5kIjoidXZ4IiwiYXJncyI6WyItLWZyb20iLCJnaXRjb2RlLWFwaVttY3BdIiwiZ2l0Y29kZS1hcGkiLCJzZXJ2ZSJdLCJlbnYiOnsiR0lUQ09ERV9BQ0NFU1NfVE9LRU4iOiIke2lucHV0OmdpdGNvZGVfYWNjZXNzX3Rva2VufSJ9LCJpbnB1dHMiOlt7ImlkIjoiZ2l0Y29kZV9hY2Nlc3NfdG9rZW4iLCJ0eXBlIjoicHJvbXB0U3RyaW5nIiwiZGVzY3JpcHRpb24iOiJFbnRlciBHSVRDT0RFX0FDQ0VTU19UT0tFTiIsInBhc3N3b3JkIjp0cnVlfV19) [![Install in VS Code](https://img.shields.io/badge/Install_in-VS_Code-0098FF?logo=visualstudiocode&logoColor=white)](https://vscode.dev/redirect/mcp/install?name=GitCode%20API&config=%7B%22command%22%3A%22uvx%22%2C%22args%22%3A%5B%22--from%22%2C%22gitcode-api%5Bmcp%5D%22%2C%22gitcode-api%22%2C%22serve%22%5D%2C%22env%22%3A%7B%22GITCODE_ACCESS_TOKEN%22%3A%22%24%7Binput%3Agitcode_access_token%7D%22%7D%2C%22inputs%22%3A%5B%7B%22id%22%3A%22gitcode_access_token%22%2C%22type%22%3A%22promptString%22%2C%22description%22%3A%22Enter%20GITCODE_ACCESS_TOKEN%22%2C%22password%22%3Atrue%7D%5D%7D)
42
42
  [![GitHub Badge](https://img.shields.io/badge/github-repo-blue?logo=github&link=https%3A%2F%2Fgithub.com%2FTrenza1ore%2FGitCode-API)](https://github.com/Trenza1ore/GitCode-API) [![GitCode Badge](https://img.shields.io/badge/gitcode-repo-brown?logo=gitcode&link=https%3A%2F%2Fgitcode.com%2FSushiNinja%2FGitCode-API)](https://gitcode.com/SushiNinja/GitCode-API)
43
43
 
44
44
  [![Docs](https://img.shields.io/badge/%E6%96%87%E6%A1%A3-Docs-cyan?style=for-the-badge&logo=readthedocs&link=https%3A%2F%2Fgitcode-api.readthedocs.io%2Fen%2Flatest%2Findex.html)](https://gitcode-api.readthedocs.io) [![中文README](https://img.shields.io/badge/%E4%B8%AD%E6%96%87-README-brown?style=for-the-badge&logo=googledocs&link=README.zh.md)](README.zh.md)
45
45
 
46
- `gitcode-api` is a community-maintained Python SDK for the GitCode REST API. It provides easy-to-use synchronous and asynchronous clients, repository-scoped helpers, and lightweight response models so you can work with GitCode from Python without hand-writing raw HTTP requests. The `gitcode_api.llm` module adds an OpenAI-style function tool and MCP service so agents can reuse the same resource-oriented API.
46
+ `gitcode-api` is a community-maintained Python SDK for the GitCode REST API. It provides easy-to-use synchronous and asynchronous clients, repository-scoped helpers, and lightweight response models so you can work with GitCode from Python without hand-writing raw HTTP requests. The `gitcode_api.llm` module adds an OpenAI-style function tool, an MCP service, and an [openJiuwen](https://openjiuwen.com) tool integration so agents can reuse the same resource-oriented API.
47
47
 
48
48
  ## Why This Project
49
49
 
@@ -52,8 +52,9 @@ Dynamic: license-file
52
52
  - Resource groups such as `client.repos`, `client.pulls`, and `client.users`.
53
53
  - Repository defaults via `owner=` and `repo=` on the client.
54
54
  - Sphinx docs plus a mirrored GitCode REST API reference in `docs/`.
55
- - Provides MCP server & OpenAI tool for LLM agent usage.
55
+ - Provides MCP server, OpenAI tool, and [openJiuwen](https://openjiuwen.com) tool for LLM agent usage.
56
56
  - Provide MCP service that directly installs to your IDE of choice, such as Cursor and VS Code!
57
+ - Provides an [mcpb bundle](https://www.anthropic.com/engineering/desktop-extensions) you can install directly in the Claude desktop app; download it from [Release](https://github.com/Trenza1ore/GitCode-API/releases/latest).
57
58
 
58
59
  ## Installation
59
60
 
@@ -64,11 +65,11 @@ pip install -U gitcode-api
64
65
  ```
65
66
 
66
67
  Install the MCP server to your AI-powered IDE of choice:
68
+
67
69
  [![Install in Cursor](https://img.shields.io/badge/Install_in-Cursor-000000?style=flat-square&logoColor=white)](https://cursor.com/en/install-mcp?name=GitCode%20API&config=eyJjb21tYW5kIjoidXZ4IiwiYXJncyI6WyItLWZyb20iLCJnaXRjb2RlLWFwaVttY3BdIiwiZ2l0Y29kZS1hcGkiLCJzZXJ2ZSJdLCJlbnYiOnsiR0lUQ09ERV9BQ0NFU1NfVE9LRU4iOiIke2lucHV0OmdpdGNvZGVfYWNjZXNzX3Rva2VufSJ9LCJpbnB1dHMiOlt7ImlkIjoiZ2l0Y29kZV9hY2Nlc3NfdG9rZW4iLCJ0eXBlIjoicHJvbXB0U3RyaW5nIiwiZGVzY3JpcHRpb24iOiJFbnRlciBHSVRDT0RFX0FDQ0VTU19UT0tFTiIsInBhc3N3b3JkIjp0cnVlfV19)
68
70
  [![Install in VS Code](https://img.shields.io/badge/Install_in-VS_Code-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://vscode.dev/redirect/mcp/install?name=GitCode%20API&config=%7B%22command%22%3A%22uvx%22%2C%22args%22%3A%5B%22--from%22%2C%22gitcode-api%5Bmcp%5D%22%2C%22gitcode-api%22%2C%22serve%22%5D%2C%22env%22%3A%7B%22GITCODE_ACCESS_TOKEN%22%3A%22%24%7Binput%3Agitcode_access_token%7D%22%7D%2C%22inputs%22%3A%5B%7B%22id%22%3A%22gitcode_access_token%22%2C%22type%22%3A%22promptString%22%2C%22description%22%3A%22Enter%20GITCODE_ACCESS_TOKEN%22%2C%22password%22%3Atrue%7D%5D%7D)
69
71
  [![Install in VS Code Insiders](https://img.shields.io/badge/Install_in-VS_Code_Insiders-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=GitCode%20API&config=%7B%22command%22%3A%22uvx%22%2C%22args%22%3A%5B%22--from%22%2C%22gitcode-api%5Bmcp%5D%22%2C%22gitcode-api%22%2C%22serve%22%5D%2C%22env%22%3A%7B%22GITCODE_ACCESS_TOKEN%22%3A%22%24%7Binput%3Agitcode_access_token%7D%22%7D%2C%22inputs%22%3A%5B%7B%22id%22%3A%22gitcode_access_token%22%2C%22type%22%3A%22promptString%22%2C%22description%22%3A%22Enter%20GITCODE_ACCESS_TOKEN%22%2C%22password%22%3Atrue%7D%5D%7D&quality=insiders)
70
72
  [![Install in Visual Studio](https://img.shields.io/badge/Install_in-Visual_Studio-C16FDE?style=flat-square&logo=visualstudio&logoColor=white)](https://vs-open.link/mcp-install?%7B%22command%22%3A%22uvx%22%2C%22args%22%3A%5B%22--from%22%2C%22gitcode-api%5Bmcp%5D%22%2C%22gitcode-api%22%2C%22serve%22%5D%2C%22env%22%3A%7B%22GITCODE_ACCESS_TOKEN%22%3A%22%24%7Binput%3Agitcode_access_token%7D%22%7D%2C%22inputs%22%3A%5B%7B%22id%22%3A%22gitcode_access_token%22%2C%22type%22%3A%22promptString%22%2C%22description%22%3A%22Enter%20GITCODE_ACCESS_TOKEN%22%2C%22password%22%3Atrue%7D%5D%7D)
71
- [![Install in Goose](https://block.github.io/goose/img/extension-install-dark.svg)](https://block.github.io/goose/extension?cmd=uvx&arg=--from%2520gitcode-api%5Bmcp%5D%2520gitcode-api%2520serve&id=GitCode%20API&name=GitCode%20API&description=MCP%20Server%20for%20GitCode%20API)
72
73
  [![Add MCP Server GitCode API to LM Studio](https://files.lmstudio.ai/deeplink/mcp-install-light.svg)](https://lmstudio.ai/install-mcp?name=GitCode%20API&config=eyJjb21tYW5kIjoidXZ4IiwiYXJncyI6WyItLWZyb20iLCJnaXRjb2RlLWFwaVttY3BdIiwiZ2l0Y29kZS1hcGkiLCJzZXJ2ZSJdLCJlbnYiOnsiR0lUQ09ERV9BQ0NFU1NfVE9LRU4iOiIke2lucHV0OmdpdGNvZGVfYWNjZXNzX3Rva2VufSJ9LCJpbnB1dHMiOlt7ImlkIjoiZ2l0Y29kZV9hY2Nlc3NfdG9rZW4iLCJ0eXBlIjoicHJvbXB0U3RyaW5nIiwiZGVzY3JpcHRpb24iOiJFbnRlciBHSVRDT0RFX0FDQ0VTU19UT0tFTiIsInBhc3N3b3JkIjp0cnVlfV19)
73
74
 
74
75
  For detailed setup (including installing to services like Claude Code / Codex): see [install_mcp_server.md](install_mcp_server.md).
@@ -228,7 +229,7 @@ Both `GitCode` and `AsyncGitCode` expose:
228
229
 
229
230
  Every resource group inherits a cached `methods` property from the shared resource base: a `tuple` of public callable names in stable SDK order (underscore-segment sort key, not plain A–Z on the full identifier). Private names and the introspection helpers `methods` and `method_signature` are omitted. For example, `client.pulls.methods` helps with discovery or tooling without reading the full manual list. For one method’s parameters and return type, call `client.pulls.method_signature("list_issues")` (a cached string from `inspect.signature`, with `gitcode_api._models.` stripped from annotations).
230
231
 
231
- ## LLM tools and MCP
232
+ ## LLM tools, MCP, and openJiuwen
232
233
 
233
234
  The `gitcode_api.llm` module exposes a single logical tool, **`gitcode_api_tool`**, that routes calls to sync or async SDK resources. Model-facing parameters match the JSON schema used by OpenAI-style function tools:
234
235
 
@@ -239,11 +240,11 @@ The `gitcode_api.llm` module exposes a single logical tool, **`gitcode_api_tool`
239
240
  | `params` | Keyword arguments for the method as a JSON object; omitted or `null` is treated as `{}`. |
240
241
  | `help` | When `true`, returns formatted help (available methods or a target signature) instead of performing a normal API call where applicable. |
241
242
 
242
- 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.
243
244
 
244
245
  ### OpenAI tool (`GitCodeOpenAITool`)
245
246
 
246
- 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.
247
248
 
248
249
  ```python
249
250
  from gitcode_api.llm import GitCodeOpenAITool
@@ -264,33 +265,43 @@ and handle tool calls directly:
264
265
 
265
266
  ```python
266
267
  import json
267
- from openai import OpenAI
268
- from gitcode_api.llm import GitCodeOpenAITool
268
+ import os
269
+ from typing import Dict, List
269
270
 
270
- tools = {
271
- "gitcode_api_tool": GitCodeOpenAITool(owner="SushiNinja", repo="GitCode-API"),
272
- }
273
- client = OpenAI(
274
- api_key="your-openai-compatible-api-key",
275
- base_url="https://your-openai-compatible-base-url/v1",
276
- )
271
+ from openai import OpenAI
277
272
 
278
- response = client.chat.completions.create(
279
- model="gpt-4.1-mini",
280
- messages=[{"role": "user", "content": "List the last 5 commits."}],
281
- tools=[tools["gitcode_api_tool"].tool],
282
- )
273
+ from gitcode_api.llm import GitCodeOpenAITool
283
274
 
284
- for tool_call in response.choices[0].message.tool_calls:
285
- selected_tool = tools[tool_call.function.name]
286
- print(f"Calling tool {tool_call.function.name}({tool_call.function.arguments}):")
287
- print("---result---")
288
- print(selected_tool(**json.loads(tool_call.function.arguments)))
289
- 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
290
303
  ```
291
304
 
292
- 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).
293
-
294
305
  ### MCP server and MCP tool (FastMCP)
295
306
 
296
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):
@@ -315,6 +326,24 @@ The same server is available from the CLI as `gitcode-api serve` (see the [CLI](
315
326
 
316
327
  To share auth or clients across tools, build `GitCodeLLMTool` once (`from gitcode_api.llm._tool import GitCodeLLMTool`) and pass it as `tool=` into `GitCodeMCP`, `create_mcp_server`, `register_mcp_gitcode_api_tool`, or `create_mcp_gitcode_api_tool`.
317
328
 
329
+ ### openJiuwen (`LocalFunction`)
330
+
331
+ [openJiuwen](https://openjiuwen.com) is an open agent platform. With the separate `openjiuwen` package installed (**Python 3.11+**), `create_openjiuwen_gitcode_api_tool` returns an openJiuwen `LocalFunction` that uses the same `op_type` / `action` / `params` / `help` arguments as the OpenAI adapter. Invocation is async-only (`await jiuwen_tool.invoke({...})`).
332
+
333
+ ```bash
334
+ pip install openjiuwen
335
+ ```
336
+
337
+ ```python
338
+ from gitcode_api.llm import create_openjiuwen_gitcode_api_tool
339
+
340
+ jiuwen_tool = create_openjiuwen_gitcode_api_tool(owner="SushiNinja", repo="GitCode-API")
341
+ # jiuwen_tool.card — name, description, input_params
342
+ # await jiuwen_tool.invoke({"op_type": "repos", "action": "get", "params": {}})
343
+ ```
344
+
345
+ Optional `name=` and `description=` override the default tool card. Constructor options otherwise mirror `GitCode` / `AsyncGitCode` (`client=`, `async_client=`, `api_key=`, `owner=`, `repo=`, `base_url=`, `timeout=`, `decrypt=`).
346
+
318
347
  **Claude Desktop (MCPB):** published GitHub Releases include a `gitcode-<version>.mcpb` bundle for one-click installation as a Claude Desktop extension; see Anthropic’s guide, [Build a desktop extension with MCPB](https://claude.com/docs/connectors/building/mcpb). From a checkout you can run `make mcpb` (requires the [`@anthropic-ai/mcpb`](https://www.npmjs.com/package/@anthropic-ai/mcpb) CLI on your `PATH`).
319
348
 
320
349
  ## Examples
@@ -378,7 +407,7 @@ with GitCode(
378
407
 
379
408
  Use `httpx.AsyncClient(verify=...)` with `AsyncGitCode` for async code.
380
409
 
381
- The OpenAI tool (`GitCodeOpenAITool`) and MCP helpers accept the same `client=` / `async_client=` arguments (or a shared `GitCodeLLMTool` via `tool=` with those clients set). Build `GitCode` / `AsyncGitCode` with your custom `http_client` once and pass it through so LLM tool calls reuse the same TLS settings.
410
+ The OpenAI tool (`GitCodeOpenAITool`), MCP helpers, and `create_openjiuwen_gitcode_api_tool` accept the same `client=` / `async_client=` arguments (OpenAI and MCP also accept a shared `GitCodeLLMTool` via `tool=`). Build `GitCode` / `AsyncGitCode` with your custom `http_client` once and pass it through so LLM tool calls reuse the same TLS settings.
382
411
 
383
412
  ## Project Status
384
413
 
@@ -21,6 +21,7 @@ gitcode_api.egg-info/requires.txt
21
21
  gitcode_api.egg-info/top_level.txt
22
22
  gitcode_api/llm/__init__.py
23
23
  gitcode_api/llm/_tool.py
24
+ gitcode_api/llm/jiuwen.py
24
25
  gitcode_api/llm/mcp.py
25
26
  gitcode_api/llm/openai.py
26
27
  gitcode_api/resources/__init__.py
@@ -1,10 +1,10 @@
1
1
  [project]
2
2
  name = "gitcode-api"
3
- version = "1.2.8"
4
- description = "Easy to use Python SDK for the GitCode REST API. Providing builtin CLI tool, and optional LLM integration (MCP and OpenAI tool) for agents. Community-maintained."
3
+ version = "1.2.10"
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",
7
- "mcp", "agent", "fastmcp", "llm", "mcp client", "mcp server", "model context protocol",
7
+ "mcp", "agent", "fastmcp", "llm", "openjiuwen", "mcp client", "mcp server", "model context protocol",
8
8
  ]
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9,<4"
@@ -1,3 +1,5 @@
1
+ import importlib.util
2
+ import json
1
3
  from typing import Any, Dict
2
4
 
3
5
  import httpx
@@ -7,6 +9,7 @@ from gitcode_api.llm import (
7
9
  GitCodeOpenAITool,
8
10
  create_mcp_gitcode_api_tool,
9
11
  create_mcp_server,
12
+ create_openjiuwen_gitcode_api_tool,
10
13
  register_mcp_gitcode_api_tool,
11
14
  )
12
15
  from gitcode_api.llm._tool import (
@@ -42,7 +45,7 @@ def test_openai_tool_invokes_sync_client(sync_client_factory: Any) -> None:
42
45
  http_client.close()
43
46
 
44
47
  assert "/repos/SushiNinja/GitCode-API" in captured["url"]
45
- assert result == {"full_name": "SushiNinja/GitCode-API"}
48
+ assert json.loads(result) == {"full_name": "SushiNinja/GitCode-API"}
46
49
 
47
50
 
48
51
  @pytest.mark.asyncio
@@ -61,7 +64,7 @@ async def test_openai_tool_invokes_async_client(async_client_factory: Any) -> No
61
64
  await http_client.aclose()
62
65
 
63
66
  assert "/users/octocat" in captured["url"]
64
- assert result == {"login": "octocat"}
67
+ assert json.loads(result) == {"login": "octocat"}
65
68
 
66
69
 
67
70
  def test_tool_help_does_not_require_api_key(monkeypatch: Any) -> None:
@@ -127,18 +130,6 @@ def test_help_resource_index_body() -> None:
127
130
  assert f"gitcode-api://help/{name}" in body
128
131
 
129
132
 
130
- @pytest.mark.asyncio
131
- async def test_create_mcp_server_registers_help_resources() -> None:
132
- mcp = create_mcp_server()
133
- static = await mcp.list_resources()
134
- templates = await mcp.list_resource_templates()
135
- assert any(str(r.uri) == "gitcode-api://help" for r in static)
136
- assert any("{op_type}" in str(t.uri_template) for t in templates)
137
- read = await mcp.read_resource("gitcode-api://help/pulls")
138
- payload = read.contents[0].content
139
- assert "Resource: pulls" in payload
140
-
141
-
142
133
  def test_mcp_registers_with_existing_server() -> None:
143
134
  class DummyMCP:
144
135
  def __init__(self) -> None:
@@ -156,3 +147,53 @@ def test_mcp_registers_with_existing_server() -> None:
156
147
 
157
148
  assert registered.__name__ == "gitcode_api_tool"
158
149
  assert server.registered[0]["name"] == "gitcode_api_tool"
150
+
151
+
152
+ @pytest.mark.skipif(importlib.util.find_spec("openjiuwen") is not None, reason="openjiuwen is installed")
153
+ def test_create_openjiuwen_gitcode_api_tool_raises_when_openjiuwen_missing() -> None:
154
+ with pytest.raises(ImportError, match="openjiuwen|openJiuwen"):
155
+ create_openjiuwen_gitcode_api_tool(api_key="test-token")
156
+
157
+
158
+ @pytest.mark.skipif(importlib.util.find_spec("openjiuwen") is None, reason="openjiuwen not installed")
159
+ def test_create_openjiuwen_gitcode_api_tool_exposes_tool_card() -> None:
160
+ jiuwen_tool = create_openjiuwen_gitcode_api_tool(api_key="test-token")
161
+ assert jiuwen_tool.card.name == "gitcode_api_tool"
162
+ assert "op_type" in jiuwen_tool.card.input_params.get("properties", {})
163
+
164
+
165
+ @pytest.mark.skipif(importlib.util.find_spec("openjiuwen") is None, reason="openjiuwen not installed")
166
+ def test_create_openjiuwen_gitcode_api_tool_custom_name_and_description() -> None:
167
+ jiuwen_tool = create_openjiuwen_gitcode_api_tool(
168
+ api_key="test-token",
169
+ name="my_gitcode",
170
+ description="Custom GitCode tool copy.",
171
+ )
172
+ assert jiuwen_tool.card.name == "my_gitcode"
173
+ assert jiuwen_tool.card.description == "Custom GitCode tool copy."
174
+
175
+
176
+ @pytest.mark.skipif(importlib.util.find_spec("openjiuwen") is None, reason="openjiuwen not installed")
177
+ @pytest.mark.asyncio
178
+ async def test_create_openjiuwen_gitcode_api_tool_invoke(async_client_factory: Any) -> None:
179
+ captured: Dict[str, Any] = {}
180
+
181
+ def handler(request: httpx.Request) -> httpx.Response:
182
+ captured["url"] = str(request.url)
183
+ return httpx.Response(200, json={"full_name": "SushiNinja/GitCode-API"})
184
+
185
+ client, http_client = async_client_factory(handler)
186
+ try:
187
+ jiuwen_tool = create_openjiuwen_gitcode_api_tool(async_client=client)
188
+ result = await jiuwen_tool.invoke(
189
+ {
190
+ "op_type": "repos",
191
+ "action": "get",
192
+ "params": {"owner": "SushiNinja", "repo": "GitCode-API"},
193
+ }
194
+ )
195
+ finally:
196
+ await http_client.aclose()
197
+
198
+ assert "/repos/SushiNinja/GitCode-API" in captured["url"]
199
+ assert result == {"full_name": "SushiNinja/GitCode-API"}
@@ -1 +0,0 @@
1
- 1.2.8
File without changes
File without changes