mirror of
https://github.com/tiennm99/DocsGPT.git
synced 2026-10-15 16:14:16 +00:00
Connect services from one wizard, with no tokens in the browser
Every entry point (the Connectors page and drawer, Add Source, Add Tool, the chat) opens one connect wizard: sign in or paste the credentials, choose what to sync (content services only, skippable), then a summary with Try it in chat. Tool services create their tools on sign-in with write actions needing approval, and each action's permission (Always allow, Needs approval, Off) can be changed in the wizard or the drawer. The drawer also reconnects, syncs more content, refreshes an MCP server's tools and removes a connection, keeping or deleting what it feeds. The file pickers work from a connection id and fetch a short-lived picker token when they need one; no session token is kept in localStorage any more, and any left by an older build is claimed once and removed. S3 and Reddit reuse the keys stored on a connection. A tool whose account needs signing in pauses on a Connect card in the chat; after connecting, Continue resumes the call. A connection whose sign-in stops working raises a Reconnect toast. The Connectors page is hidden when the backend does not report connectors_enabled.
This commit is contained in:
1 parent
3511004f50
commit
6e2ee43944
43 files changed
+2989
-555
No files matched your search
@@ -1649,7 +1649,7 @@ class ToolExecutor:
|
||||
# Keys the client needs that are not part of the fixed shape below. They are
|
||||
# small and optional, and are copied only when present so an ordinary tool
|
||||
# call does not grow null columns in every persisted row.
|
||||
_PRESERVED_TOOL_CALL_KEYS = ("artifacts", "device_id")
|
||||
_PRESERVED_TOOL_CALL_KEYS = ("artifacts", "device_id", "connector_key", "connector_name", "access")
|
||||
|
||||
def get_truncated_tool_calls(self) -> List[Dict]:
|
||||
"""Project tool calls into the shape that is streamed and persisted.
|
||||
|
||||
@@ -347,13 +347,29 @@ def _link_api_key_tools(bind) -> None:
|
||||
|
||||
def _downgrade_credentials() -> None:
|
||||
"""Decrypt the envelopes back into the pre-0038 plaintext columns."""
|
||||
|
||||
from sqlalchemy import text
|
||||
|
||||
|
||||
bind = op.get_bind()
|
||||
has_envelope = bind.execute(
|
||||
text(
|
||||
"SELECT 1 FROM information_schema.columns "
|
||||
"WHERE table_name = 'connector_sessions' AND column_name = 'encrypted_credentials'"
|
||||
)
|
||||
).first()
|
||||
if has_envelope is not None:
|
||||
_decrypt_back(bind)
|
||||
_restore_account_index()
|
||||
|
||||
|
||||
def _decrypt_back(bind) -> None:
|
||||
import json
|
||||
|
||||
from sqlalchemy import text
|
||||
|
||||
from docsgpt.security.encryption import CredentialDecryptionError, decrypt_json
|
||||
|
||||
bind = op.get_bind()
|
||||
# Tools keep their v1 secrets; connections made only for them go away.
|
||||
bind.execute(text("UPDATE user_tools SET connection_id = NULL WHERE connection_id IN "
|
||||
"(SELECT id FROM connector_sessions WHERE auth_kind = 'api_key')"))
|
||||
@@ -384,6 +400,9 @@ def _downgrade_credentials() -> None:
|
||||
"id": row.id,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
def _restore_account_index() -> None:
|
||||
# Several accounts per provider cannot survive the old unique index: keep
|
||||
# the most recently updated one.
|
||||
op.execute(
|
||||
|
||||
Reference in new issue
Block a user