appkit-assistant 0.15.4__tar.gz → 0.16.0__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.
- {appkit_assistant-0.15.4 → appkit_assistant-0.16.0}/PKG-INFO +1 -1
- {appkit_assistant-0.15.4 → appkit_assistant-0.16.0}/pyproject.toml +1 -1
- {appkit_assistant-0.15.4 → appkit_assistant-0.16.0}/src/appkit_assistant/backend/processor.py +19 -0
- {appkit_assistant-0.15.4 → appkit_assistant-0.16.0}/src/appkit_assistant/backend/processors/openai_responses_processor.py +6 -2
- appkit_assistant-0.16.0/src/appkit_assistant/components/mcp_oauth.py +46 -0
- appkit_assistant-0.16.0/src/appkit_assistant/pages.py +17 -0
- appkit_assistant-0.16.0/src/appkit_assistant/state/mcp_oauth_state.py +222 -0
- {appkit_assistant-0.15.4 → appkit_assistant-0.16.0}/.gitignore +0 -0
- {appkit_assistant-0.15.4 → appkit_assistant-0.16.0}/README.md +0 -0
- {appkit_assistant-0.15.4 → appkit_assistant-0.16.0}/docs/assistant.png +0 -0
- {appkit_assistant-0.15.4 → appkit_assistant-0.16.0}/src/appkit_assistant/backend/mcp_auth_service.py +0 -0
- {appkit_assistant-0.15.4 → appkit_assistant-0.16.0}/src/appkit_assistant/backend/model_manager.py +0 -0
- {appkit_assistant-0.15.4 → appkit_assistant-0.16.0}/src/appkit_assistant/backend/models.py +0 -0
- {appkit_assistant-0.15.4 → appkit_assistant-0.16.0}/src/appkit_assistant/backend/processors/lorem_ipsum_processor.py +0 -0
- {appkit_assistant-0.15.4 → appkit_assistant-0.16.0}/src/appkit_assistant/backend/processors/openai_base.py +0 -0
- {appkit_assistant-0.15.4 → appkit_assistant-0.16.0}/src/appkit_assistant/backend/processors/openai_chat_completion_processor.py +0 -0
- {appkit_assistant-0.15.4 → appkit_assistant-0.16.0}/src/appkit_assistant/backend/processors/perplexity_processor.py +0 -0
- {appkit_assistant-0.15.4 → appkit_assistant-0.16.0}/src/appkit_assistant/backend/repositories.py +0 -0
- {appkit_assistant-0.15.4 → appkit_assistant-0.16.0}/src/appkit_assistant/backend/services/thread_service.py +0 -0
- {appkit_assistant-0.15.4 → appkit_assistant-0.16.0}/src/appkit_assistant/backend/system_prompt_cache.py +0 -0
- {appkit_assistant-0.15.4 → appkit_assistant-0.16.0}/src/appkit_assistant/components/__init__.py +0 -0
- {appkit_assistant-0.15.4 → appkit_assistant-0.16.0}/src/appkit_assistant/components/composer.py +0 -0
- {appkit_assistant-0.15.4 → appkit_assistant-0.16.0}/src/appkit_assistant/components/composer_key_handler.py +0 -0
- {appkit_assistant-0.15.4 → appkit_assistant-0.16.0}/src/appkit_assistant/components/mcp_server_dialogs.py +0 -0
- {appkit_assistant-0.15.4 → appkit_assistant-0.16.0}/src/appkit_assistant/components/mcp_server_table.py +0 -0
- {appkit_assistant-0.15.4 → appkit_assistant-0.16.0}/src/appkit_assistant/components/message.py +0 -0
- {appkit_assistant-0.15.4 → appkit_assistant-0.16.0}/src/appkit_assistant/components/system_prompt_editor.py +0 -0
- {appkit_assistant-0.15.4 → appkit_assistant-0.16.0}/src/appkit_assistant/components/thread.py +0 -0
- {appkit_assistant-0.15.4 → appkit_assistant-0.16.0}/src/appkit_assistant/components/threadlist.py +0 -0
- {appkit_assistant-0.15.4 → appkit_assistant-0.16.0}/src/appkit_assistant/components/tools_modal.py +0 -0
- {appkit_assistant-0.15.4 → appkit_assistant-0.16.0}/src/appkit_assistant/configuration.py +0 -0
- {appkit_assistant-0.15.4 → appkit_assistant-0.16.0}/src/appkit_assistant/logic/response_accumulator.py +0 -0
- {appkit_assistant-0.15.4 → appkit_assistant-0.16.0}/src/appkit_assistant/state/mcp_server_state.py +0 -0
- {appkit_assistant-0.15.4 → appkit_assistant-0.16.0}/src/appkit_assistant/state/system_prompt_state.py +0 -0
- {appkit_assistant-0.15.4 → appkit_assistant-0.16.0}/src/appkit_assistant/state/thread_list_state.py +0 -0
- {appkit_assistant-0.15.4 → appkit_assistant-0.16.0}/src/appkit_assistant/state/thread_state.py +0 -0
{appkit_assistant-0.15.4 → appkit_assistant-0.16.0}/src/appkit_assistant/backend/processor.py
RENAMED
|
@@ -7,9 +7,28 @@ import logging
|
|
|
7
7
|
from collections.abc import AsyncGenerator
|
|
8
8
|
|
|
9
9
|
from appkit_assistant.backend.models import AIModel, Chunk, MCPServer, Message
|
|
10
|
+
from appkit_commons.configuration.configuration import ReflexConfig
|
|
11
|
+
from appkit_commons.registry import service_registry
|
|
10
12
|
|
|
11
13
|
logger = logging.getLogger(__name__)
|
|
12
14
|
|
|
15
|
+
# OAuth callback path - must match registered redirect URIs
|
|
16
|
+
MCP_OAUTH_CALLBACK_PATH = "/assistant/mcp/callback"
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def mcp_oauth_redirect_uri() -> str:
|
|
20
|
+
"""Build the MCP OAuth redirect URI from configuration."""
|
|
21
|
+
reflex_config: ReflexConfig | None = service_registry().get(ReflexConfig)
|
|
22
|
+
if reflex_config:
|
|
23
|
+
base_url = reflex_config.deploy_url
|
|
24
|
+
port = reflex_config.frontend_port
|
|
25
|
+
# Only add port if not standard (80 for http, 443 for https)
|
|
26
|
+
if port and port not in (80, 443):
|
|
27
|
+
return f"{base_url}:{port}{MCP_OAUTH_CALLBACK_PATH}"
|
|
28
|
+
return f"{base_url}{MCP_OAUTH_CALLBACK_PATH}"
|
|
29
|
+
# Fallback for development
|
|
30
|
+
return f"http://localhost:8080{MCP_OAUTH_CALLBACK_PATH}"
|
|
31
|
+
|
|
13
32
|
|
|
14
33
|
class Processor(abc.ABC):
|
|
15
34
|
"""Base processor interface for AI processing services."""
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import json
|
|
2
2
|
import logging
|
|
3
3
|
from collections.abc import AsyncGenerator
|
|
4
|
-
from typing import Any
|
|
4
|
+
from typing import Any, Final
|
|
5
5
|
|
|
6
6
|
import reflex as rx
|
|
7
7
|
|
|
@@ -16,11 +16,13 @@ from appkit_assistant.backend.models import (
|
|
|
16
16
|
Message,
|
|
17
17
|
MessageType,
|
|
18
18
|
)
|
|
19
|
+
from appkit_assistant.backend.processor import mcp_oauth_redirect_uri
|
|
19
20
|
from appkit_assistant.backend.processors.openai_base import BaseOpenAIProcessor
|
|
20
21
|
from appkit_assistant.backend.system_prompt_cache import get_system_prompt
|
|
21
22
|
from appkit_commons.database.session import get_session_manager
|
|
22
23
|
|
|
23
24
|
logger = logging.getLogger(__name__)
|
|
25
|
+
default_oauth_redirect_uri: Final[str] = mcp_oauth_redirect_uri()
|
|
24
26
|
|
|
25
27
|
|
|
26
28
|
class OpenAIResponsesProcessor(BaseOpenAIProcessor):
|
|
@@ -32,7 +34,7 @@ class OpenAIResponsesProcessor(BaseOpenAIProcessor):
|
|
|
32
34
|
api_key: str | None = None,
|
|
33
35
|
base_url: str | None = None,
|
|
34
36
|
is_azure: bool = False,
|
|
35
|
-
oauth_redirect_uri: str =
|
|
37
|
+
oauth_redirect_uri: str = default_oauth_redirect_uri,
|
|
36
38
|
) -> None:
|
|
37
39
|
super().__init__(models, api_key, base_url, is_azure)
|
|
38
40
|
self._current_reasoning_session: str | None = None
|
|
@@ -40,6 +42,8 @@ class OpenAIResponsesProcessor(BaseOpenAIProcessor):
|
|
|
40
42
|
self._mcp_auth_service = MCPAuthService(redirect_uri=oauth_redirect_uri)
|
|
41
43
|
self._pending_auth_servers: list[MCPServer] = []
|
|
42
44
|
|
|
45
|
+
logger.debug("Using redirect URI for MCP OAuth: %s", oauth_redirect_uri)
|
|
46
|
+
|
|
43
47
|
async def process(
|
|
44
48
|
self,
|
|
45
49
|
messages: list[Message],
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import reflex as rx
|
|
2
|
+
|
|
3
|
+
from appkit_assistant.state.mcp_oauth_state import MCPOAuthState
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def mcp_oauth_callback_content() -> rx.Component:
|
|
7
|
+
"""Content for the MCP OAuth callback page."""
|
|
8
|
+
return rx.center(
|
|
9
|
+
rx.card(
|
|
10
|
+
rx.vstack(
|
|
11
|
+
rx.cond(
|
|
12
|
+
MCPOAuthState.status == "processing",
|
|
13
|
+
rx.fragment(
|
|
14
|
+
rx.spinner(size="3"),
|
|
15
|
+
rx.text(MCPOAuthState.message, size="3"),
|
|
16
|
+
),
|
|
17
|
+
rx.cond(
|
|
18
|
+
MCPOAuthState.status == "success",
|
|
19
|
+
rx.fragment(
|
|
20
|
+
rx.icon("circle-check", size=48, color="green"),
|
|
21
|
+
rx.text(MCPOAuthState.message, size="3", weight="medium"),
|
|
22
|
+
rx.text(
|
|
23
|
+
"Dieses Fenster wird automatisch geschlossen.",
|
|
24
|
+
size="2",
|
|
25
|
+
color="gray",
|
|
26
|
+
),
|
|
27
|
+
),
|
|
28
|
+
rx.fragment(
|
|
29
|
+
rx.icon("circle-alert", size=48, color="red"),
|
|
30
|
+
rx.text(MCPOAuthState.message, size="3", weight="medium"),
|
|
31
|
+
rx.button(
|
|
32
|
+
"Fenster schließen",
|
|
33
|
+
on_click=rx.call_script("window.close()"),
|
|
34
|
+
variant="soft",
|
|
35
|
+
),
|
|
36
|
+
),
|
|
37
|
+
),
|
|
38
|
+
),
|
|
39
|
+
align="center",
|
|
40
|
+
spacing="4",
|
|
41
|
+
padding="6",
|
|
42
|
+
),
|
|
43
|
+
size="3",
|
|
44
|
+
),
|
|
45
|
+
height="100vh",
|
|
46
|
+
)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import reflex as rx
|
|
2
|
+
|
|
3
|
+
from appkit_assistant.components.mcp_oauth import mcp_oauth_callback_content
|
|
4
|
+
from appkit_assistant.state.mcp_oauth_state import MCPOAuthState
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@rx.page(
|
|
8
|
+
route="/assistant/mcp/callback",
|
|
9
|
+
title="MCP Verbindung",
|
|
10
|
+
on_load=MCPOAuthState.handle_mcp_oauth_callback,
|
|
11
|
+
)
|
|
12
|
+
def mcp_oauth_callback_page() -> rx.Component:
|
|
13
|
+
"""MCP OAuth callback page."""
|
|
14
|
+
return rx.theme(
|
|
15
|
+
mcp_oauth_callback_content(),
|
|
16
|
+
has_background=True,
|
|
17
|
+
)
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
"""MCP OAuth callback page and state.
|
|
2
|
+
|
|
3
|
+
Handles OAuth redirects from MCP server identity providers.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import contextlib
|
|
7
|
+
import logging
|
|
8
|
+
from collections.abc import AsyncGenerator
|
|
9
|
+
|
|
10
|
+
import reflex as rx
|
|
11
|
+
from sqlmodel import Session, select
|
|
12
|
+
|
|
13
|
+
from appkit_assistant.backend.mcp_auth_service import MCPAuthService
|
|
14
|
+
from appkit_assistant.backend.models import MCPServer
|
|
15
|
+
from appkit_assistant.backend.processor import mcp_oauth_redirect_uri
|
|
16
|
+
from appkit_commons.database.session import get_session_manager
|
|
17
|
+
from appkit_user.authentication.backend.entities import OAuthStateEntity
|
|
18
|
+
from appkit_user.authentication.states import UserSession
|
|
19
|
+
|
|
20
|
+
logger = logging.getLogger(__name__)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class MCPOAuthState(rx.State):
|
|
24
|
+
"""State for handling MCP OAuth callbacks."""
|
|
25
|
+
|
|
26
|
+
# UI state
|
|
27
|
+
status: str = "processing" # processing, success, error
|
|
28
|
+
message: str = "Verarbeite Anmeldung..."
|
|
29
|
+
server_name: str = ""
|
|
30
|
+
|
|
31
|
+
# Stored from URL params
|
|
32
|
+
_code: str = ""
|
|
33
|
+
_state: str = ""
|
|
34
|
+
_server_id: int | None = None
|
|
35
|
+
|
|
36
|
+
@rx.event
|
|
37
|
+
async def handle_mcp_oauth_callback(self) -> AsyncGenerator:
|
|
38
|
+
"""Handle the OAuth callback from an MCP server's identity provider."""
|
|
39
|
+
# Get query params from router (using new router.url API)
|
|
40
|
+
params = self.router.url.query_parameters
|
|
41
|
+
code = params.get("code", "")
|
|
42
|
+
state = params.get("state", "")
|
|
43
|
+
server_id_str = params.get("server_id", "")
|
|
44
|
+
|
|
45
|
+
logger.info(
|
|
46
|
+
"MCP OAuth callback - params: %s, code: '%s', state: '%s', server_id: '%s'",
|
|
47
|
+
params,
|
|
48
|
+
code[:20] if code else "None",
|
|
49
|
+
state,
|
|
50
|
+
server_id_str,
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
if not code:
|
|
54
|
+
self.status = "error"
|
|
55
|
+
self.message = "Kein Autorisierungscode erhalten."
|
|
56
|
+
yield
|
|
57
|
+
return
|
|
58
|
+
|
|
59
|
+
# If server_id is missing, try to recover it from state
|
|
60
|
+
if not server_id_str and state:
|
|
61
|
+
with get_session_manager().session() as session:
|
|
62
|
+
oauth_state = (
|
|
63
|
+
session.execute(
|
|
64
|
+
select(OAuthStateEntity).where(OAuthStateEntity.state == state)
|
|
65
|
+
)
|
|
66
|
+
.scalars()
|
|
67
|
+
.first()
|
|
68
|
+
)
|
|
69
|
+
logger.info(
|
|
70
|
+
"OAuth state lookup - found: %s, provider: %s",
|
|
71
|
+
oauth_state is not None,
|
|
72
|
+
oauth_state.provider if oauth_state else "N/A",
|
|
73
|
+
)
|
|
74
|
+
if oauth_state and oauth_state.provider.startswith("mcp:"):
|
|
75
|
+
with contextlib.suppress(IndexError):
|
|
76
|
+
server_id_str = oauth_state.provider.split(":")[1]
|
|
77
|
+
logger.debug(
|
|
78
|
+
"Recovered server_id from state: %s", server_id_str
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
if not server_id_str:
|
|
82
|
+
self.status = "error"
|
|
83
|
+
self.message = "Server-ID fehlt."
|
|
84
|
+
yield
|
|
85
|
+
return
|
|
86
|
+
|
|
87
|
+
try:
|
|
88
|
+
server_id = int(server_id_str)
|
|
89
|
+
except ValueError:
|
|
90
|
+
self.status = "error"
|
|
91
|
+
self.message = "Ungültige Server-ID."
|
|
92
|
+
yield
|
|
93
|
+
return
|
|
94
|
+
|
|
95
|
+
self._code = code
|
|
96
|
+
self._state = state
|
|
97
|
+
self._server_id = server_id
|
|
98
|
+
|
|
99
|
+
# Get the server configuration
|
|
100
|
+
with rx.session() as session:
|
|
101
|
+
server = session.exec(
|
|
102
|
+
select(MCPServer).where(MCPServer.id == server_id)
|
|
103
|
+
).first()
|
|
104
|
+
|
|
105
|
+
if not server:
|
|
106
|
+
self.status = "error"
|
|
107
|
+
self.message = "Server nicht gefunden."
|
|
108
|
+
yield
|
|
109
|
+
return
|
|
110
|
+
|
|
111
|
+
self.server_name = server.name
|
|
112
|
+
|
|
113
|
+
# Get user ID from auth state
|
|
114
|
+
user_id = await self._get_current_user_id()
|
|
115
|
+
if not user_id:
|
|
116
|
+
self.status = "error"
|
|
117
|
+
self.message = "Nicht angemeldet."
|
|
118
|
+
yield
|
|
119
|
+
return
|
|
120
|
+
|
|
121
|
+
# Exchange code for tokens - inline the logic to avoid yield from
|
|
122
|
+
async for result in self._do_token_exchange(
|
|
123
|
+
session, server, user_id, code, self._state
|
|
124
|
+
):
|
|
125
|
+
yield result
|
|
126
|
+
|
|
127
|
+
async def _do_token_exchange(
|
|
128
|
+
self,
|
|
129
|
+
session: Session,
|
|
130
|
+
server: MCPServer,
|
|
131
|
+
user_id: int,
|
|
132
|
+
code: str,
|
|
133
|
+
state: str,
|
|
134
|
+
) -> AsyncGenerator:
|
|
135
|
+
"""Exchange the authorization code for tokens."""
|
|
136
|
+
redirect_uri = self._build_redirect_uri()
|
|
137
|
+
auth_service = MCPAuthService(redirect_uri=redirect_uri)
|
|
138
|
+
|
|
139
|
+
try:
|
|
140
|
+
result = await auth_service.exchange_code_for_tokens(
|
|
141
|
+
server, code, state=state, session=session
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
if result.error:
|
|
145
|
+
self.status = "error"
|
|
146
|
+
self.message = (
|
|
147
|
+
f"Token-Austausch fehlgeschlagen: {result.error_description}"
|
|
148
|
+
)
|
|
149
|
+
yield
|
|
150
|
+
return
|
|
151
|
+
|
|
152
|
+
# Save the token
|
|
153
|
+
auth_service.save_user_token(
|
|
154
|
+
session,
|
|
155
|
+
user_id,
|
|
156
|
+
server.id, # type: ignore
|
|
157
|
+
result,
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
self.status = "success"
|
|
161
|
+
self.message = f"Erfolgreich mit {server.name} verbunden!"
|
|
162
|
+
yield
|
|
163
|
+
|
|
164
|
+
# Notify parent window via localStorage (works across windows)
|
|
165
|
+
# Include user_id for security - prevents cross-user leakage
|
|
166
|
+
server_id_str = str(server.id)
|
|
167
|
+
logger.debug(
|
|
168
|
+
"OAuth success - notifying via localStorage: "
|
|
169
|
+
"server_id=%s, name=%s, user_id=%s",
|
|
170
|
+
server_id_str,
|
|
171
|
+
server.name,
|
|
172
|
+
user_id,
|
|
173
|
+
)
|
|
174
|
+
script = f"""
|
|
175
|
+
console.log('[OAuth] Setting localStorage for cross-window sync');
|
|
176
|
+
var data = JSON.stringify({{
|
|
177
|
+
type: 'mcp-oauth-success',
|
|
178
|
+
serverId: '{server_id_str}',
|
|
179
|
+
serverName: '{server.name}',
|
|
180
|
+
userId: '{user_id}',
|
|
181
|
+
timestamp: Date.now()
|
|
182
|
+
}});
|
|
183
|
+
localStorage.setItem('mcp-oauth-result', data);
|
|
184
|
+
console.log('[OAuth] localStorage set:', data);
|
|
185
|
+
// Also try postMessage for same-origin popups
|
|
186
|
+
if (window.opener) {{
|
|
187
|
+
window.opener.postMessage({{
|
|
188
|
+
type: 'mcp-oauth-success',
|
|
189
|
+
serverId: '{server_id_str}',
|
|
190
|
+
serverName: '{server.name}',
|
|
191
|
+
userId: '{user_id}'
|
|
192
|
+
}}, '*');
|
|
193
|
+
}}
|
|
194
|
+
setTimeout(function() {{ window.close(); }}, 500);
|
|
195
|
+
"""
|
|
196
|
+
yield rx.call_script(script)
|
|
197
|
+
|
|
198
|
+
except Exception as e:
|
|
199
|
+
logger.exception("Token exchange failed")
|
|
200
|
+
self.status = "error"
|
|
201
|
+
self.message = f"Fehler: {e!s}"
|
|
202
|
+
yield
|
|
203
|
+
|
|
204
|
+
finally:
|
|
205
|
+
await auth_service.close()
|
|
206
|
+
|
|
207
|
+
async def _get_current_user_id(self) -> int | None:
|
|
208
|
+
"""Get the current user's ID from auth state."""
|
|
209
|
+
auth_state = await self.get_state(UserSession)
|
|
210
|
+
# Verify authentication status to ensure user_id is populated from session token
|
|
211
|
+
await auth_state.authenticated_user
|
|
212
|
+
if auth_state.user_id and auth_state.user_id > 0:
|
|
213
|
+
return auth_state.user_id
|
|
214
|
+
return None
|
|
215
|
+
|
|
216
|
+
def _build_redirect_uri(self) -> str:
|
|
217
|
+
"""Build the OAuth redirect URI from configuration.
|
|
218
|
+
|
|
219
|
+
Uses the same configuration-based URL as the authorization request
|
|
220
|
+
to ensure redirect_uri matches exactly.
|
|
221
|
+
"""
|
|
222
|
+
return mcp_oauth_redirect_uri()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{appkit_assistant-0.15.4 → appkit_assistant-0.16.0}/src/appkit_assistant/backend/mcp_auth_service.py
RENAMED
|
File without changes
|
{appkit_assistant-0.15.4 → appkit_assistant-0.16.0}/src/appkit_assistant/backend/model_manager.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{appkit_assistant-0.15.4 → appkit_assistant-0.16.0}/src/appkit_assistant/backend/repositories.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{appkit_assistant-0.15.4 → appkit_assistant-0.16.0}/src/appkit_assistant/components/__init__.py
RENAMED
|
File without changes
|
{appkit_assistant-0.15.4 → appkit_assistant-0.16.0}/src/appkit_assistant/components/composer.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{appkit_assistant-0.15.4 → appkit_assistant-0.16.0}/src/appkit_assistant/components/message.py
RENAMED
|
File without changes
|
|
File without changes
|
{appkit_assistant-0.15.4 → appkit_assistant-0.16.0}/src/appkit_assistant/components/thread.py
RENAMED
|
File without changes
|
{appkit_assistant-0.15.4 → appkit_assistant-0.16.0}/src/appkit_assistant/components/threadlist.py
RENAMED
|
File without changes
|
{appkit_assistant-0.15.4 → appkit_assistant-0.16.0}/src/appkit_assistant/components/tools_modal.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{appkit_assistant-0.15.4 → appkit_assistant-0.16.0}/src/appkit_assistant/state/mcp_server_state.py
RENAMED
|
File without changes
|
|
File without changes
|
{appkit_assistant-0.15.4 → appkit_assistant-0.16.0}/src/appkit_assistant/state/thread_list_state.py
RENAMED
|
File without changes
|
{appkit_assistant-0.15.4 → appkit_assistant-0.16.0}/src/appkit_assistant/state/thread_state.py
RENAMED
|
File without changes
|