appkit-assistant 1.0.0__tar.gz → 1.0.2__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-1.0.0 → appkit_assistant-1.0.2}/PKG-INFO +1 -1
- {appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/pyproject.toml +1 -1
- {appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/backend/processors/gemini_responses_processor.py +88 -82
- {appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/state/thread_list_state.py +1 -1
- {appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/.gitignore +0 -0
- {appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/README.md +0 -0
- {appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/docs/assistant.png +0 -0
- {appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/backend/database/models.py +0 -0
- {appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/backend/database/repositories.py +0 -0
- {appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/backend/model_manager.py +0 -0
- {appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/backend/models/__init__.py +0 -0
- {appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/backend/models/anthropic.py +0 -0
- {appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/backend/models/google.py +0 -0
- {appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/backend/models/openai.py +0 -0
- {appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/backend/models/perplexity.py +0 -0
- {appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/backend/processors/__init__.py +0 -0
- {appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/backend/processors/claude_responses_processor.py +0 -0
- {appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/backend/processors/lorem_ipsum_processor.py +0 -0
- {appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/backend/processors/mcp_mixin.py +0 -0
- {appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/backend/processors/openai_base.py +0 -0
- {appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/backend/processors/openai_chat_completion_processor.py +0 -0
- {appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/backend/processors/openai_responses_processor.py +0 -0
- {appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/backend/processors/perplexity_processor.py +0 -0
- {appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/backend/processors/processor_base.py +0 -0
- {appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/backend/processors/streaming_base.py +0 -0
- {appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/backend/schemas.py +0 -0
- {appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/backend/services/auth_error_detector.py +0 -0
- {appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/backend/services/chunk_factory.py +0 -0
- {appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/backend/services/citation_handler.py +0 -0
- {appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/backend/services/file_cleanup_service.py +0 -0
- {appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/backend/services/file_manager.py +0 -0
- {appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/backend/services/file_upload_service.py +0 -0
- {appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/backend/services/file_validation.py +0 -0
- {appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/backend/services/mcp_auth_service.py +0 -0
- {appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/backend/services/mcp_token_service.py +0 -0
- {appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/backend/services/message_converter.py +0 -0
- {appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/backend/services/openai_client_service.py +0 -0
- {appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/backend/services/response_accumulator.py +0 -0
- {appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/backend/services/system_prompt_builder.py +0 -0
- {appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/backend/services/thread_service.py +0 -0
- {appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/backend/system_prompt_cache.py +0 -0
- {appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/components/__init__.py +0 -0
- {appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/components/composer.py +0 -0
- {appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/components/composer_key_handler.py +0 -0
- {appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/components/file_manager.py +0 -0
- {appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/components/mcp_oauth.py +0 -0
- {appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/components/mcp_server_dialogs.py +0 -0
- {appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/components/mcp_server_table.py +0 -0
- {appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/components/message.py +0 -0
- {appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/components/system_prompt_editor.py +0 -0
- {appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/components/thread.py +0 -0
- {appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/components/threadlist.py +0 -0
- {appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/components/tools_modal.py +0 -0
- {appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/configuration.py +0 -0
- {appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/pages.py +0 -0
- {appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/state/file_manager_state.py +0 -0
- {appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/state/mcp_oauth_state.py +0 -0
- {appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/state/mcp_server_state.py +0 -0
- {appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/state/system_prompt_state.py +0 -0
- {appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/state/thread_state.py +0 -0
|
@@ -21,10 +21,8 @@ from appkit_assistant.backend.database.models import (
|
|
|
21
21
|
MCPServer,
|
|
22
22
|
)
|
|
23
23
|
from appkit_assistant.backend.processors.mcp_mixin import MCPCapabilities
|
|
24
|
-
from appkit_assistant.backend.processors.processor_base import
|
|
25
|
-
|
|
26
|
-
mcp_oauth_redirect_uri,
|
|
27
|
-
)
|
|
24
|
+
from appkit_assistant.backend.processors.processor_base import mcp_oauth_redirect_uri
|
|
25
|
+
from appkit_assistant.backend.processors.streaming_base import StreamingProcessorBase
|
|
28
26
|
from appkit_assistant.backend.schemas import (
|
|
29
27
|
AIModel,
|
|
30
28
|
Chunk,
|
|
@@ -32,7 +30,6 @@ from appkit_assistant.backend.schemas import (
|
|
|
32
30
|
Message,
|
|
33
31
|
MessageType,
|
|
34
32
|
)
|
|
35
|
-
from appkit_assistant.backend.services.chunk_factory import ChunkFactory
|
|
36
33
|
from appkit_assistant.backend.services.system_prompt_builder import SystemPromptBuilder
|
|
37
34
|
|
|
38
35
|
logger = logging.getLogger(__name__)
|
|
@@ -98,7 +95,7 @@ class MCPSessionWrapper(NamedTuple):
|
|
|
98
95
|
name: str
|
|
99
96
|
|
|
100
97
|
|
|
101
|
-
class GeminiResponsesProcessor(
|
|
98
|
+
class GeminiResponsesProcessor(StreamingProcessorBase, MCPCapabilities):
|
|
102
99
|
"""Gemini processor using the GenAI API with native MCP support."""
|
|
103
100
|
|
|
104
101
|
def __init__(
|
|
@@ -107,10 +104,9 @@ class GeminiResponsesProcessor(ProcessorBase, MCPCapabilities):
|
|
|
107
104
|
api_key: str | None = None,
|
|
108
105
|
oauth_redirect_uri: str = default_oauth_redirect_uri,
|
|
109
106
|
) -> None:
|
|
107
|
+
StreamingProcessorBase.__init__(self, models, "gemini_responses")
|
|
110
108
|
MCPCapabilities.__init__(self, oauth_redirect_uri, "gemini_responses")
|
|
111
|
-
self.models = models
|
|
112
109
|
self.client: genai.Client | None = None
|
|
113
|
-
self._chunk_factory = ChunkFactory(processor_name="gemini_responses")
|
|
114
110
|
self._system_prompt_builder = SystemPromptBuilder()
|
|
115
111
|
|
|
116
112
|
if api_key:
|
|
@@ -125,9 +121,9 @@ class GeminiResponsesProcessor(ProcessorBase, MCPCapabilities):
|
|
|
125
121
|
|
|
126
122
|
logger.debug("Using redirect URI for MCP OAuth: %s", oauth_redirect_uri)
|
|
127
123
|
|
|
128
|
-
def
|
|
129
|
-
"""Get
|
|
130
|
-
return
|
|
124
|
+
def _get_event_handlers(self) -> dict[str, Any]:
|
|
125
|
+
"""Get event handlers (empty for Gemini - uses chunk-based handling)."""
|
|
126
|
+
return {}
|
|
131
127
|
|
|
132
128
|
async def process(
|
|
133
129
|
self,
|
|
@@ -194,7 +190,7 @@ class GeminiResponsesProcessor(ProcessorBase, MCPCapabilities):
|
|
|
194
190
|
|
|
195
191
|
except Exception as e:
|
|
196
192
|
logger.exception("Error in Gemini processor: %s", str(e))
|
|
197
|
-
yield self.
|
|
193
|
+
yield self.chunk_factory.error(f"Error: {e!s}")
|
|
198
194
|
|
|
199
195
|
async def _create_mcp_sessions(
|
|
200
196
|
self, servers: list[MCPServer], user_id: int | None
|
|
@@ -316,89 +312,99 @@ class GeminiResponsesProcessor(ProcessorBase, MCPCapabilities):
|
|
|
316
312
|
logger.info("Processing cancelled by user")
|
|
317
313
|
break
|
|
318
314
|
|
|
319
|
-
|
|
315
|
+
# Use streaming API
|
|
316
|
+
stream = await self.client.aio.models.generate_content_stream(
|
|
320
317
|
model=model_name, contents=current_contents, config=config
|
|
321
318
|
)
|
|
322
319
|
|
|
323
|
-
|
|
320
|
+
# Collect function calls and stream text as it arrives
|
|
321
|
+
collected_function_calls: list[Any] = []
|
|
322
|
+
collected_parts: list[types.Part] = []
|
|
323
|
+
streamed_text = ""
|
|
324
|
+
|
|
325
|
+
async for chunk in stream:
|
|
326
|
+
if cancellation_token and cancellation_token.is_set():
|
|
327
|
+
logger.info("Processing cancelled by user")
|
|
328
|
+
return
|
|
329
|
+
|
|
330
|
+
if not chunk.candidates or not chunk.candidates[0].content:
|
|
331
|
+
continue
|
|
332
|
+
|
|
333
|
+
for part in chunk.candidates[0].content.parts:
|
|
334
|
+
# Stream text immediately
|
|
335
|
+
if part.text:
|
|
336
|
+
streamed_text += part.text
|
|
337
|
+
yield self.chunk_factory.text(part.text, delta=part.text)
|
|
338
|
+
# Collect function calls
|
|
339
|
+
if part.function_call is not None:
|
|
340
|
+
collected_function_calls.append(part.function_call)
|
|
341
|
+
collected_parts.append(part)
|
|
342
|
+
|
|
343
|
+
# If no function calls, we're done (text was already streamed)
|
|
344
|
+
if not collected_function_calls:
|
|
324
345
|
return
|
|
325
346
|
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
]
|
|
335
|
-
|
|
336
|
-
if function_calls:
|
|
337
|
-
# Add model response with function calls to conversation
|
|
338
|
-
current_contents.append(content)
|
|
339
|
-
|
|
340
|
-
# Execute tool calls and collect results
|
|
341
|
-
function_responses = []
|
|
342
|
-
for fc in function_calls:
|
|
343
|
-
# Parse unique tool name: server_name__tool_name
|
|
344
|
-
server_name, original_tool_name = self._parse_unique_tool_name(
|
|
345
|
-
fc.name
|
|
346
|
-
)
|
|
347
|
-
|
|
348
|
-
# Generate a unique tool call ID
|
|
349
|
-
tool_call_id = f"mcp_{uuid.uuid4().hex[:32]}"
|
|
347
|
+
# Build the model's response content with function calls
|
|
348
|
+
model_response_parts = []
|
|
349
|
+
if streamed_text:
|
|
350
|
+
model_response_parts.append(types.Part(text=streamed_text))
|
|
351
|
+
model_response_parts.extend(collected_parts)
|
|
352
|
+
current_contents.append(
|
|
353
|
+
types.Content(role="model", parts=model_response_parts)
|
|
354
|
+
)
|
|
350
355
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
356
|
+
# Execute tool calls and collect results
|
|
357
|
+
function_responses = []
|
|
358
|
+
for fc in collected_function_calls:
|
|
359
|
+
# Parse unique tool name: server_name__tool_name
|
|
360
|
+
server_name, original_tool_name = self._parse_unique_tool_name(fc.name)
|
|
361
|
+
|
|
362
|
+
# Generate a unique tool call ID
|
|
363
|
+
tool_call_id = f"mcp_{uuid.uuid4().hex[:32]}"
|
|
364
|
+
|
|
365
|
+
# Yield TOOL_CALL chunk to show in UI (use original name)
|
|
366
|
+
yield self.chunk_factory.tool_call(
|
|
367
|
+
f"Benutze Werkzeug: {server_name}.{original_tool_name}",
|
|
368
|
+
tool_name=original_tool_name,
|
|
369
|
+
tool_id=tool_call_id,
|
|
370
|
+
server_label=server_name,
|
|
371
|
+
status="starting",
|
|
372
|
+
)
|
|
359
373
|
|
|
360
|
-
|
|
361
|
-
fc.name, fc.args, tool_contexts
|
|
362
|
-
)
|
|
374
|
+
result = await self._execute_mcp_tool(fc.name, fc.args, tool_contexts)
|
|
363
375
|
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
376
|
+
# Yield TOOL_RESULT chunk with preview
|
|
377
|
+
preview = (
|
|
378
|
+
result[:TOOL_RESULT_PREVIEW_LENGTH]
|
|
379
|
+
if len(result) > TOOL_RESULT_PREVIEW_LENGTH
|
|
380
|
+
else result
|
|
381
|
+
)
|
|
382
|
+
yield self.chunk_factory.tool_result(
|
|
383
|
+
preview,
|
|
384
|
+
tool_id=tool_call_id,
|
|
385
|
+
status="completed",
|
|
386
|
+
)
|
|
375
387
|
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
)
|
|
388
|
+
function_responses.append(
|
|
389
|
+
types.Part(
|
|
390
|
+
function_response=types.FunctionResponse(
|
|
391
|
+
name=fc.name,
|
|
392
|
+
response={"result": result},
|
|
382
393
|
)
|
|
383
394
|
)
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
)
|
|
389
|
-
|
|
390
|
-
# Add function responses
|
|
391
|
-
current_contents.append(
|
|
392
|
-
types.Content(role="user", parts=function_responses)
|
|
395
|
+
)
|
|
396
|
+
logger.debug(
|
|
397
|
+
"Tool %s executed, result length: %d",
|
|
398
|
+
fc.name,
|
|
399
|
+
len(str(result)),
|
|
393
400
|
)
|
|
394
401
|
|
|
395
|
-
|
|
396
|
-
|
|
402
|
+
# Add function responses
|
|
403
|
+
current_contents.append(
|
|
404
|
+
types.Content(role="user", parts=function_responses)
|
|
405
|
+
)
|
|
397
406
|
|
|
398
|
-
#
|
|
399
|
-
if text := self._extract_text_from_parts(content.parts):
|
|
400
|
-
yield self._chunk_factory.text(text, delta=text)
|
|
401
|
-
return
|
|
407
|
+
# Continue to next round
|
|
402
408
|
|
|
403
409
|
logger.warning("Max tool rounds (%d) exceeded", max_tool_rounds)
|
|
404
410
|
|
|
@@ -668,5 +674,5 @@ class GeminiResponsesProcessor(ProcessorBase, MCPCapabilities):
|
|
|
668
674
|
return None
|
|
669
675
|
|
|
670
676
|
if text := self._extract_text_from_parts(chunk.candidates[0].content.parts):
|
|
671
|
-
return self.
|
|
677
|
+
return self.chunk_factory.text(text, delta=text)
|
|
672
678
|
return None
|
{appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/state/thread_list_state.py
RENAMED
|
@@ -69,7 +69,7 @@ class ThreadListState(rx.State):
|
|
|
69
69
|
async def initialize(self) -> AsyncGenerator[Any, Any]:
|
|
70
70
|
"""Initialize thread list - load summaries from database."""
|
|
71
71
|
async with self:
|
|
72
|
-
if self._initialized:
|
|
72
|
+
if self._initialized or self.loading:
|
|
73
73
|
return
|
|
74
74
|
self.loading = True
|
|
75
75
|
yield
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/backend/database/models.py
RENAMED
|
File without changes
|
|
File without changes
|
{appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/backend/model_manager.py
RENAMED
|
File without changes
|
{appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/backend/models/__init__.py
RENAMED
|
File without changes
|
{appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/backend/models/anthropic.py
RENAMED
|
File without changes
|
{appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/backend/models/google.py
RENAMED
|
File without changes
|
{appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/backend/models/openai.py
RENAMED
|
File without changes
|
{appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/backend/models/perplexity.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/components/__init__.py
RENAMED
|
File without changes
|
{appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/components/composer.py
RENAMED
|
File without changes
|
|
File without changes
|
{appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/components/file_manager.py
RENAMED
|
File without changes
|
{appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/components/mcp_oauth.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/components/message.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/components/threadlist.py
RENAMED
|
File without changes
|
{appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/components/tools_modal.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/state/file_manager_state.py
RENAMED
|
File without changes
|
{appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/state/mcp_oauth_state.py
RENAMED
|
File without changes
|
{appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/state/mcp_server_state.py
RENAMED
|
File without changes
|
{appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/state/system_prompt_state.py
RENAMED
|
File without changes
|
{appkit_assistant-1.0.0 → appkit_assistant-1.0.2}/src/appkit_assistant/state/thread_state.py
RENAMED
|
File without changes
|