Files
Maries c6f83a63e1 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>
2025-07-23 13:49:01 +08:00

209 lines
5.2 KiB
Python

from collections.abc import Mapping
from decimal import Decimal
from enum import Enum
from pydantic import BaseModel, ConfigDict, Field, field_validator
from dify_plugin.entities.model import BaseModelConfig, ModelType, ModelUsage, PriceInfo
from dify_plugin.entities.model.message import (
AssistantPromptMessage,
PromptMessage,
)
class LLMMode(Enum):
"""
Enum class for large language model mode.
"""
COMPLETION = "completion"
CHAT = "chat"
@classmethod
def value_of(cls, value: str) -> "LLMMode":
"""
Get value of given mode.
:param value: mode value
:return: mode
"""
for mode in cls:
if mode.value == value:
return mode
raise ValueError(f"invalid mode value {value}")
class LLMUsage(ModelUsage):
"""
Model class for llm usage.
"""
prompt_tokens: int
prompt_unit_price: Decimal
prompt_price_unit: Decimal
prompt_price: Decimal
completion_tokens: int
completion_unit_price: Decimal
completion_price_unit: Decimal
completion_price: Decimal
total_tokens: int
total_price: Decimal
currency: str
latency: float
@classmethod
def empty_usage(cls):
return cls(
prompt_tokens=0,
prompt_unit_price=Decimal("0.0"),
prompt_price_unit=Decimal("0.0"),
prompt_price=Decimal("0.0"),
completion_tokens=0,
completion_unit_price=Decimal("0.0"),
completion_price_unit=Decimal("0.0"),
completion_price=Decimal("0.0"),
total_tokens=0,
total_price=Decimal("0.0"),
currency="USD",
latency=0.0,
)
class LLMResultChunkDelta(BaseModel):
"""
Model class for llm result chunk delta.
"""
index: int
message: AssistantPromptMessage
usage: LLMUsage | None = None
finish_reason: str | None = None
class LLMResultChunk(BaseModel):
"""
Model class for llm result chunk.
"""
model: str
prompt_messages: list[PromptMessage] = Field(default_factory=list)
system_fingerprint: str | None = None
delta: LLMResultChunkDelta
@field_validator("prompt_messages", mode="before")
@classmethod
def transform_prompt_messages(cls, value):
"""
ISSUE:
- https://github.com/langgenius/dify/issues/17799
- https://github.com/langgenius/dify-official-plugins/issues/648
The `prompt_messages` field is deprecated, but to keep backward compatibility
we need to always set it to an empty list.
NOTE: just do not use it anymore, it will be removed in the future.
"""
return []
class LLMStructuredOutput(BaseModel):
"""
Model class for llm structured output.
"""
structured_output: Mapping | None = None
class LLMResultChunkWithStructuredOutput(LLMResultChunk, LLMStructuredOutput):
"""
Model class for llm result chunk with structured output.
"""
pass
class LLMResult(BaseModel):
"""
Model class for llm result.
"""
model: str
prompt_messages: list[PromptMessage] = Field(default_factory=list)
message: AssistantPromptMessage
usage: LLMUsage
system_fingerprint: str | None = None
@field_validator("prompt_messages", mode="before")
@classmethod
def transform_prompt_messages(cls, value):
"""
ISSUE:
- https://github.com/langgenius/dify/issues/17799
- https://github.com/langgenius/dify-official-plugins/issues/648
The `prompt_messages` field is deprecated, but to keep backward compatibility
we need to always set it to an empty list.
NOTE: just do not use it anymore, it will be removed in the future.
"""
return []
def to_llm_result_chunk(self) -> "LLMResultChunk":
return LLMResultChunk(
model=self.model,
system_fingerprint=self.system_fingerprint,
delta=LLMResultChunkDelta(
index=0,
message=self.message,
usage=self.usage,
finish_reason=None,
),
)
class LLMResultWithStructuredOutput(LLMResult, LLMStructuredOutput):
"""
Model class for llm result with structured output.
"""
def to_llm_result_chunk_with_structured_output(self) -> "LLMResultChunkWithStructuredOutput":
return LLMResultChunkWithStructuredOutput(
model=self.model,
system_fingerprint=self.system_fingerprint,
delta=LLMResultChunkDelta(
index=0,
message=self.message,
usage=self.usage,
finish_reason=None,
),
structured_output=self.structured_output,
)
class SummaryResult(BaseModel):
"""
Model class for summary result.
"""
summary: str
class NumTokensResult(PriceInfo):
"""
Model class for number of tokens result.
"""
tokens: int
class LLMModelConfig(BaseModelConfig):
"""
Model class for llm model config.
"""
model_type: ModelType = ModelType.LLM
mode: str
completion_params: dict = Field(default_factory=dict)
model_config = ConfigDict(protected_namespaces=())