mirror of
https://github.com/langgenius/dify-plugin-sdks.git
synced 2026-07-22 18:35:29 -04:00
feat[0.4.2]: Tool OAuth (#179)
* chore: fix ruff issue * feat(oauth): implement OAuth * feat(invoke-message): refactor message handling and introduce InvokeMessage class * feat(plugin-oauth): add credential_id and credential_type to tool parameters * feat(plugin-oauth): add credential_id and credential_type to tool parameters * chore: update dify_plugin version to 0.5.0b4 and clean up github.yaml * chore: update plugin version to 0.1.2 in manifest.yaml * feat(session): session context and tool backwards invocation credential support * feat(oauth): session context and tool backwards invocation credential support * feat: update README and requirements for OAuth support in version 0.4.2 * feat: add .gitignore to exclude IDE files and secret keys * chore: apply ruff * feat: bump version to 0.4.2b1 * feat: update GitHub plugin configuration for OAuth support and improve credential handling * feat: update .gitignore to exclude dify plugin files and public keys * feat: fix credential validation for GitHub API and bump version to 0.2.1 * feat: update GitHub plugin to support multiple access tokens and bump version to 0.2.5 * chore: apply ruff * feat: add ToolProviderOAuthError for improved OAuth error handling in GitHub plugin * chore: apply ruff * chore: bump version to 0.4.2 * chore: update examples sdk version to 0.4.2 * fix: thread deadlock in PluginRunner when running tests without gevent monkey patching * feat: add support for refreshing OAuth credentials in Plugin and GitHub provider * feat: refactor OAuth credential handling to return structured OAuthCredentials object * apply ruff * feat: refactor OAuth credential handling to use ToolOAuthCredentials for improved structure * feat: reorganize imports in __init__.py for improved clarity and structure * feat: add Microsoft To Do plugin for refresh token example * chore: apply ruff * fix: update author in GitHub configuration and clean up Microsoft To Do schema * chore: bump version to 0.4.2b2 in pyproject.toml * feat: update Microsoft To Do plugin to handle OAuth token encoding and version bump * feat:remove inelegant example * chore: update dify_plugin version to 0.4.2 * chore: bump version to 0.4.2 in pyproject.toml --------- Co-authored-by: Yeuoly <admin@srmxy.cn>
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
import json
|
||||
from collections.abc import Generator
|
||||
from typing import Any
|
||||
|
||||
import requests
|
||||
|
||||
from dify_plugin import Tool
|
||||
from dify_plugin.entities.provider_config import CredentialType
|
||||
from dify_plugin.entities.tool import ToolInvokeMessage
|
||||
from dify_plugin.errors.model import InvokeError
|
||||
|
||||
|
||||
class GithubSearchCodeTool(Tool):
|
||||
def _invoke(self, tool_parameters: dict[str, Any]) -> Generator[ToolInvokeMessage, None, None]:
|
||||
"""
|
||||
invoke tools
|
||||
"""
|
||||
query = tool_parameters.get("query", "")
|
||||
per_page = tool_parameters.get("per_page", 10)
|
||||
sort = tool_parameters.get("sort", "")
|
||||
order = tool_parameters.get("order", "desc")
|
||||
|
||||
credential_type = self.runtime.credential_type
|
||||
|
||||
if not query:
|
||||
yield self.create_text_message("Please input search query")
|
||||
return
|
||||
|
||||
if credential_type == CredentialType.API_KEY and "access_tokens" not in self.runtime.credentials:
|
||||
yield self.create_text_message("GitHub API Access Tokens is required.")
|
||||
return
|
||||
|
||||
if credential_type == CredentialType.OAUTH and "access_tokens" not in self.runtime.credentials:
|
||||
yield self.create_text_message("GitHub OAuth Access Tokens is required.")
|
||||
return
|
||||
|
||||
access_token = self.runtime.credentials.get("access_tokens")
|
||||
try:
|
||||
headers = {
|
||||
"Content-Type": "application/vnd.github+json",
|
||||
"Authorization": f"Bearer {access_token}",
|
||||
"X-GitHub-Api-Version": "2022-11-28",
|
||||
}
|
||||
s = requests.session()
|
||||
api_domain = "https://api.github.com"
|
||||
url = f"{api_domain}/search/code"
|
||||
|
||||
params = {"q": query, "per_page": per_page, "order": order}
|
||||
|
||||
if sort:
|
||||
params["sort"] = sort
|
||||
|
||||
response = s.request(
|
||||
method="GET",
|
||||
headers=headers,
|
||||
url=url,
|
||||
params=params,
|
||||
)
|
||||
|
||||
if response.status_code == 200:
|
||||
response_data = response.json()
|
||||
|
||||
total_count = response_data.get("total_count", 0)
|
||||
items = response_data.get("items", [])
|
||||
|
||||
search_results = []
|
||||
for item in items:
|
||||
result_info = {
|
||||
"name": item.get("name", ""),
|
||||
"path": item.get("path", ""),
|
||||
"sha": item.get("sha", "")[:7],
|
||||
"url": item.get("html_url", ""),
|
||||
"git_url": item.get("git_url", ""),
|
||||
"download_url": item.get("download_url", ""),
|
||||
"score": item.get("score", 0),
|
||||
"repository": {
|
||||
"id": item.get("repository", {}).get("id", 0),
|
||||
"name": item.get("repository", {}).get("name", ""),
|
||||
"full_name": item.get("repository", {}).get("full_name", ""),
|
||||
"url": item.get("repository", {}).get("html_url", ""),
|
||||
"description": item.get("repository", {}).get("description", ""),
|
||||
"language": item.get("repository", {}).get("language", ""),
|
||||
"stars": item.get("repository", {}).get("stargazers_count", 0),
|
||||
"forks": item.get("repository", {}).get("forks_count", 0),
|
||||
"is_private": item.get("repository", {}).get("private", False),
|
||||
"owner": {
|
||||
"login": item.get("repository", {}).get("owner", {}).get("login", ""),
|
||||
"type": item.get("repository", {}).get("owner", {}).get("type", ""),
|
||||
},
|
||||
},
|
||||
"text_matches": [
|
||||
{
|
||||
"fragment": match.get("fragment", ""),
|
||||
"matches": [
|
||||
{"text": m.get("text", ""), "indices": m.get("indices", [])}
|
||||
for m in match.get("matches", [])
|
||||
],
|
||||
}
|
||||
for match in item.get("text_matches", [])
|
||||
],
|
||||
}
|
||||
search_results.append(result_info)
|
||||
|
||||
result = {"total_count": total_count, "query": query, "results": search_results}
|
||||
|
||||
s.close()
|
||||
|
||||
if not search_results:
|
||||
yield self.create_text_message(f"No code found for query: {query}")
|
||||
else:
|
||||
yield self.create_text_message(
|
||||
self.session.model.summary.invoke(
|
||||
text=json.dumps(result, ensure_ascii=False),
|
||||
instruction="Summarize the GitHub code search results in a structured format",
|
||||
)
|
||||
)
|
||||
else:
|
||||
response_data = response.json()
|
||||
raise InvokeError(
|
||||
f"Request failed: {response.status_code} {response_data.get('message', 'Unknown error')}"
|
||||
)
|
||||
except InvokeError as e:
|
||||
raise e
|
||||
except Exception as e:
|
||||
raise InvokeError(f"GitHub API request failed: {e}") from e
|
||||
Reference in New Issue
Block a user