```
feat: 添加飞书用户模块和订阅功能支持 - 新增feishu_users模块用于处理飞书用户身份验证和权限管理 - 新增subscriptions模块用于处理订阅相关功能 - 新增personalization模块用于个性化服务 - 在alembic迁移配置中注册新的模型模块 - 在API路由器中添加feishu_users和subscriptions路由 - 实现事件调度服务的改进,包括错误处理和状态更新优化 - 添加飞书命令处理的权限检查机制 - 实现飞书应用票据事件处理 - 改进审计日志记录功能 ```
This commit is contained in:
@@ -1,12 +1,13 @@
|
||||
import json
|
||||
from typing import Any
|
||||
|
||||
from fastapi import HTTPException, status
|
||||
|
||||
from app.modules.ai_agent.constants import (
|
||||
CHAT_USER_CONTENT_TEMPLATE,
|
||||
COMPANY_MANAGEMENT_SYSTEM_INSTRUCTIONS,
|
||||
UNEXPECTED_HERMES_RESPONSE,
|
||||
AIChatRole,
|
||||
AIContextKey,
|
||||
AIErrorKey,
|
||||
AIHttpPayloadKey,
|
||||
AIResponseKey,
|
||||
@@ -41,6 +42,7 @@ def _chat_completion_payload(response: Any, error_key: AIErrorKey) -> dict[str,
|
||||
|
||||
|
||||
def _chat_messages(prompt: str, context: dict[str, Any] | None = None) -> list[dict[str, str]]:
|
||||
request_context = context or {}
|
||||
return [
|
||||
{
|
||||
AIHttpPayloadKey.ROLE: AIChatRole.SYSTEM,
|
||||
@@ -48,14 +50,57 @@ def _chat_messages(prompt: str, context: dict[str, Any] | None = None) -> list[d
|
||||
},
|
||||
{
|
||||
AIHttpPayloadKey.ROLE: AIChatRole.USER,
|
||||
AIHttpPayloadKey.CONTENT: CHAT_USER_CONTENT_TEMPLATE.format(
|
||||
context=context or {},
|
||||
task=prompt,
|
||||
),
|
||||
AIHttpPayloadKey.CONTENT: _ordered_context(prompt, request_context),
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
def _ordered_context(prompt: str, context: dict[str, Any]) -> str:
|
||||
"""Serialize trusted personalization layers in their required precedence."""
|
||||
|
||||
company_rules = context.get(AIContextKey.COMPANY_RULES)
|
||||
if company_rules is None:
|
||||
company_rules = context.get(AIContextKey.USER_RULES) or []
|
||||
controlled_keys = {
|
||||
AIContextKey.USER_RULES,
|
||||
AIContextKey.COMPANY_RULES,
|
||||
AIContextKey.PERSONAL_RULES,
|
||||
AIContextKey.PREFERENCES,
|
||||
AIContextKey.INTERESTS,
|
||||
AIContextKey.LOCAL_MEMORY,
|
||||
AIContextKey.CONVERSATION_HISTORY,
|
||||
AIContextKey.PROVIDER_SESSION_ID,
|
||||
AIContextKey.ALLOW_PROVIDER_MEMORY,
|
||||
}
|
||||
current_context = {
|
||||
str(key): value for key, value in context.items() if key not in controlled_keys
|
||||
}
|
||||
sections = [
|
||||
("公司规则", company_rules),
|
||||
("个人规则", context.get(AIContextKey.PERSONAL_RULES) or []),
|
||||
(
|
||||
"当前请求",
|
||||
{
|
||||
"prompt": prompt,
|
||||
"context": current_context,
|
||||
},
|
||||
),
|
||||
(
|
||||
"个人偏好与兴趣",
|
||||
{
|
||||
"preferences": context.get(AIContextKey.PREFERENCES) or [],
|
||||
"interests": context.get(AIContextKey.INTERESTS) or [],
|
||||
},
|
||||
),
|
||||
("个人相关记忆", context.get(AIContextKey.LOCAL_MEMORY) or []),
|
||||
("当前会话历史", context.get(AIContextKey.CONVERSATION_HISTORY) or []),
|
||||
]
|
||||
return "\n\n".join(
|
||||
f"{title}:\n{json.dumps(value, ensure_ascii=False, default=str)}"
|
||||
for title, value in sections
|
||||
)
|
||||
|
||||
|
||||
def _service_root(base_url: str, suffix: str) -> str:
|
||||
root = base_url.rstrip("/")
|
||||
normalized_suffix = suffix.rstrip("/")
|
||||
|
||||
@@ -15,6 +15,7 @@ from app.modules.ai_agent.constants import (
|
||||
AUTHORIZATION_BEARER_TEMPLATE,
|
||||
UNEXPECTED_HERMES_RESPONSE,
|
||||
AIErrorKey,
|
||||
AIContextKey,
|
||||
AIHttpHeader,
|
||||
AIHttpPath,
|
||||
AIHttpPayloadKey,
|
||||
@@ -38,11 +39,16 @@ class HermesAdapter(AIAdapter):
|
||||
headers[AIHttpHeader.AUTHORIZATION] = AUTHORIZATION_BEARER_TEMPLATE.format(
|
||||
token=self.settings.hermes_api_key
|
||||
)
|
||||
if self.settings.hermes_session_id:
|
||||
headers[AIHttpHeader.HERMES_SESSION_ID] = self.settings.hermes_session_id
|
||||
request_context = context or {}
|
||||
session_id = (
|
||||
request_context.get(AIContextKey.PROVIDER_SESSION_ID)
|
||||
or self.settings.hermes_session_id
|
||||
)
|
||||
if session_id:
|
||||
headers[AIHttpHeader.HERMES_SESSION_ID] = str(session_id)
|
||||
payload = {
|
||||
AIHttpPayloadKey.MODEL: self.settings.hermes_model,
|
||||
AIHttpPayloadKey.MESSAGES: _chat_messages(prompt, context),
|
||||
AIHttpPayloadKey.MESSAGES: _chat_messages(prompt, request_context),
|
||||
AIHttpPayloadKey.STREAM: False,
|
||||
}
|
||||
with httpx.Client(timeout=300, trust_env=False) as client:
|
||||
|
||||
@@ -32,7 +32,14 @@ class OpenClawHermesAdapter(AIAdapter):
|
||||
|
||||
def ask(self, prompt: str, context: dict[str, Any] | None = None) -> dict[str, Any]:
|
||||
base_context = context or {}
|
||||
recall = self._recall_memory(prompt, base_context)
|
||||
allow_provider_memory = bool(
|
||||
base_context.get(AIContextKey.ALLOW_PROVIDER_MEMORY, True)
|
||||
)
|
||||
recall = (
|
||||
self._recall_memory(prompt, base_context)
|
||||
if allow_provider_memory
|
||||
else {AIResponseKey.ANSWER: "", AIResponseKey.RAW: {}}
|
||||
)
|
||||
openclaw = self._openclaw_context(base_context)
|
||||
hermes_context = {
|
||||
**base_context,
|
||||
@@ -41,10 +48,14 @@ class OpenClawHermesAdapter(AIAdapter):
|
||||
AIContextKey.OPENCLAW: openclaw,
|
||||
}
|
||||
hermes_result = self.hermes.ask(prompt, hermes_context)
|
||||
remember = self._remember_interaction(
|
||||
prompt,
|
||||
base_context,
|
||||
hermes_result[AIResponseKey.ANSWER],
|
||||
remember = (
|
||||
self._remember_interaction(
|
||||
prompt,
|
||||
base_context,
|
||||
hermes_result[AIResponseKey.ANSWER],
|
||||
)
|
||||
if allow_provider_memory
|
||||
else {AIResponseKey.OK: False, AIResponseKey.RAW: {}}
|
||||
)
|
||||
return {
|
||||
AIResponseKey.ANSWER: hermes_result[AIResponseKey.ANSWER],
|
||||
|
||||
Reference in New Issue
Block a user