appkit-assistant 0.17.0__py3-none-any.whl → 0.17.1__py3-none-any.whl

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.
@@ -1,4 +1,5 @@
1
1
  import json
2
+ import uuid
2
3
  from datetime import UTC, datetime
3
4
  from enum import StrEnum
4
5
  from typing import Any
@@ -82,7 +83,9 @@ class MessageType(StrEnum):
82
83
 
83
84
 
84
85
  class Message(BaseModel):
86
+ id: str = Field(default_factory=lambda: str(uuid.uuid4()))
85
87
  text: str
88
+ original_text: str | None = None # To store original text if edited
86
89
  editable: bool = False
87
90
  type: MessageType
88
91
  done: bool = False
@@ -643,6 +643,9 @@ class GeminiResponsesProcessor(BaseGeminiProcessor):
643
643
  content = candidate.content
644
644
 
645
645
  # List comprehension for text parts
646
+ if not content.parts:
647
+ return None
648
+
646
649
  text_parts = [part.text for part in content.parts if part.text]
647
650
 
648
651
  if text_parts:
@@ -66,23 +66,40 @@ class OpenAIChatCompletionsProcessor(BaseOpenAIProcessor):
66
66
  if event.choices and event.choices[0].delta:
67
67
  content = event.choices[0].delta.content
68
68
  if content:
69
- yield self._create_chunk(content, model.model, stream=True)
69
+ yield self._create_chunk(
70
+ content,
71
+ model.model,
72
+ stream=True,
73
+ message_id=event.id,
74
+ )
70
75
  else:
71
76
  content = session.choices[0].message.content
72
77
  if content:
73
- yield self._create_chunk(content, model.model)
78
+ yield self._create_chunk(
79
+ content, model.model, message_id=session.id
80
+ )
74
81
  except Exception as e:
75
82
  raise e
76
83
 
77
- def _create_chunk(self, content: str, model: str, stream: bool = False) -> Chunk:
84
+ def _create_chunk(
85
+ self,
86
+ content: str,
87
+ model: str,
88
+ stream: bool = False,
89
+ message_id: str | None = None,
90
+ ) -> Chunk:
91
+ metadata = {
92
+ "source": "chat_completions",
93
+ "streaming": str(stream),
94
+ "model": model,
95
+ }
96
+ if message_id:
97
+ metadata["message_id"] = message_id
98
+
78
99
  return Chunk(
79
100
  type=ChunkType.TEXT,
80
101
  text=content,
81
- chunk_metadata={
82
- "source": "chat_completions",
83
- "streaming": str(stream),
84
- "model": model,
85
- },
102
+ chunk_metadata=metadata,
86
103
  )
87
104
 
88
105
  def _convert_messages_to_openai_format(
@@ -52,6 +52,14 @@ class ResponseAccumulator:
52
52
 
53
53
  def process_chunk(self, chunk: Chunk) -> None:
54
54
  """Process a single chunk and update internal state."""
55
+ # Update message ID if provided in metadata
56
+ if (
57
+ self.messages
58
+ and self.messages[-1].type == MessageType.ASSISTANT
59
+ and "message_id" in chunk.chunk_metadata
60
+ ):
61
+ self.messages[-1].id = chunk.chunk_metadata["message_id"]
62
+
55
63
  if chunk.type == ChunkType.TEXT:
56
64
  if self.messages and self.messages[-1].type == MessageType.ASSISTANT:
57
65
  self.messages[-1].text += chunk.text
@@ -12,6 +12,7 @@ from appkit_assistant.state.thread_state import (
12
12
  ThreadState,
13
13
  )
14
14
  from appkit_ui.components.collabsible import collabsible
15
+ from appkit_ui.components.dialogs import delete_dialog
15
16
 
16
17
  message_styles = {
17
18
  "spacing": "4",
@@ -85,6 +86,70 @@ class AuthCardComponent:
85
86
  )
86
87
 
87
88
 
89
+ class MessageActionsBar:
90
+ """Component for message action buttons (copy, download, retry)."""
91
+
92
+ @staticmethod
93
+ def render(message: Message) -> rx.Component:
94
+ return rx.hstack(
95
+ rx.tooltip(
96
+ rx.icon_button(
97
+ rx.icon("copy", size=14),
98
+ on_click=ThreadState.copy_message(message.text),
99
+ variant="ghost",
100
+ size="1",
101
+ color_scheme="gray",
102
+ ),
103
+ content="Kopieren",
104
+ ),
105
+ rx.tooltip(
106
+ rx.icon_button(
107
+ rx.icon("download", size=14),
108
+ on_click=ThreadState.download_message(message.text, message.id),
109
+ variant="ghost",
110
+ size="1",
111
+ color_scheme="gray",
112
+ ),
113
+ content="Herunterladen",
114
+ ),
115
+ rx.tooltip(
116
+ delete_dialog(
117
+ title="Nachricht löschen",
118
+ content="diese Nachricht",
119
+ on_click=ThreadState.delete_message(message.id),
120
+ icon_button=True,
121
+ variant="ghost",
122
+ size="1",
123
+ color_scheme="gray",
124
+ ),
125
+ content="Löschen",
126
+ ),
127
+ rx.cond(
128
+ (message.type == MessageType.ASSISTANT)
129
+ | (message.type == MessageType.ERROR),
130
+ rx.tooltip(
131
+ rx.icon_button(
132
+ rx.cond(
133
+ ThreadState.processing,
134
+ rx.spinner(size="1"),
135
+ rx.icon("refresh-cw", size=14),
136
+ ),
137
+ on_click=ThreadState.retry_message(message.id),
138
+ variant="ghost",
139
+ size="1",
140
+ color_scheme="gray",
141
+ disabled=ThreadState.processing,
142
+ ),
143
+ content="Erneut generieren (folgende Nachrichten werden entfernt)",
144
+ ),
145
+ rx.fragment(),
146
+ ),
147
+ spacing="3",
148
+ margin_top="-9px",
149
+ margin_left="9px",
150
+ )
151
+
152
+
88
153
  class MessageComponent:
89
154
  @staticmethod
90
155
  def _file_badge(filename: str) -> rx.Component:
@@ -116,31 +181,101 @@ class MessageComponent:
116
181
 
117
182
  @staticmethod
118
183
  def human_message(message: Message) -> rx.Component:
119
- return rx.hstack(
120
- rx.spacer(),
184
+ return rx.cond(
185
+ ThreadState.editing_message_id == message.id,
186
+ # Edit Mode
121
187
  rx.vstack(
122
- rx.box(
123
- rx.text(
124
- message.text,
125
- padding="0.5em",
126
- border_radius="10px",
127
- white_space="pre-line",
188
+ rx.text_area(
189
+ value=ThreadState.edited_message_content,
190
+ on_change=ThreadState.set_edited_message_content,
191
+ height="112px",
192
+ width="824px",
193
+ auto_focus=True,
194
+ bg=rx.color("gray", 3),
195
+ variant="soft",
196
+ ),
197
+ rx.hstack(
198
+ rx.button(
199
+ "Abbrechen",
200
+ on_click=ThreadState.cancel_edit,
201
+ variant="soft",
202
+ color_scheme="gray",
128
203
  ),
129
- padding="4px",
130
- max_width="100%",
131
- background_color=rx.color_mode_cond(
132
- light=rx.color("accent", 3),
133
- dark=rx.color("accent", 3),
204
+ rx.button("Senden", on_click=ThreadState.submit_edited_message),
205
+ justify="end",
206
+ width="100%",
207
+ spacing="2",
208
+ ),
209
+ style=message_styles,
210
+ align="end",
211
+ ),
212
+ rx.vstack(
213
+ rx.hstack(
214
+ rx.spacer(),
215
+ rx.vstack(
216
+ rx.box(
217
+ rx.text(
218
+ message.text,
219
+ padding="0.5em",
220
+ border_radius="10px",
221
+ white_space="pre-line",
222
+ ),
223
+ padding="4px",
224
+ max_width="800px",
225
+ background_color=rx.color_mode_cond(
226
+ light=rx.color("accent", 3),
227
+ dark=rx.color("accent", 3),
228
+ ),
229
+ border_radius="9px",
230
+ ),
231
+ MessageComponent._attachments_row(message.attachments),
232
+ align="end",
233
+ spacing="1",
134
234
  ),
135
- border_radius="9px",
136
235
  ),
137
- MessageComponent._attachments_row(message.attachments),
236
+ rx.hstack(
237
+ rx.spacer(),
238
+ rx.tooltip(
239
+ rx.icon_button(
240
+ rx.icon("pencil", size=14),
241
+ on_click=ThreadState.set_editing_mode(
242
+ message.id, message.text
243
+ ),
244
+ variant="ghost",
245
+ size="1",
246
+ color_scheme="gray",
247
+ ),
248
+ content="Bearbeiten",
249
+ ),
250
+ rx.tooltip(
251
+ delete_dialog(
252
+ title="Nachricht löschen",
253
+ content="diese Nachricht",
254
+ on_click=ThreadState.delete_message(message.id),
255
+ icon_button=True,
256
+ variant="ghost",
257
+ size="1",
258
+ color_scheme="gray",
259
+ ),
260
+ content="Löschen",
261
+ ),
262
+ rx.tooltip(
263
+ rx.icon_button(
264
+ rx.icon("copy", size=14),
265
+ on_click=ThreadState.copy_message(message.text),
266
+ variant="ghost",
267
+ size="1",
268
+ color_scheme="gray",
269
+ ),
270
+ content="Kopieren",
271
+ ),
272
+ spacing="3",
273
+ justify="end",
274
+ margin_right="9px",
275
+ ),
138
276
  align="end",
139
- spacing="1",
277
+ style=message_styles,
140
278
  ),
141
- max_width="80%",
142
- margin_top="24px",
143
- style=message_styles,
144
279
  )
145
280
 
146
281
  @staticmethod
@@ -190,12 +325,6 @@ class MessageComponent:
190
325
  color=rx.color("gray", 8),
191
326
  margin_right="9px",
192
327
  ),
193
- rx.hstack(
194
- rx.el.span(""),
195
- rx.el.span(""),
196
- rx.el.span(""),
197
- rx.el.span(""),
198
- ),
199
328
  class_name="loading",
200
329
  height="40px",
201
330
  color=rx.color("gray", 8),
@@ -206,23 +335,24 @@ class MessageComponent:
206
335
  padding_right="18px",
207
336
  ),
208
337
  # Actual message content
209
- mn.markdown_preview(
210
- source=message.text,
211
- enable_mermaid=message.done,
212
- enable_katex=message.done,
213
- security_level="standard",
338
+ rx.box(
339
+ mn.markdown_preview(
340
+ source=message.text,
341
+ enable_mermaid=message.done,
342
+ enable_katex=message.done,
343
+ security_level="standard",
344
+ class_name="markdown",
345
+ ),
214
346
  padding="0.5em",
215
- border_radius="9px",
347
+ margin_top="18px",
216
348
  max_width="90%",
217
- class_name="markdown",
218
349
  ),
219
- # rx.markdown(
220
- # message.text,
221
- # padding="0.5em",
222
- # border_radius="9px",
223
- # max_width="90%",
224
- # class_name="markdown",
225
- # ),
350
+ ),
351
+ # Actions bar
352
+ rx.cond(
353
+ message.done,
354
+ MessageActionsBar.render(message),
355
+ rx.fragment(),
226
356
  ),
227
357
  spacing="3",
228
358
  width="100%",
@@ -263,7 +393,7 @@ class MessageComponent:
263
393
  )
264
394
 
265
395
  @staticmethod
266
- def error_message(message: str) -> rx.Component:
396
+ def error_message(message: Message) -> rx.Component:
267
397
  return rx.hstack(
268
398
  rx.avatar(
269
399
  fallback="!",
@@ -273,15 +403,20 @@ class MessageComponent:
273
403
  margin_top="16px",
274
404
  color_scheme="red",
275
405
  ),
276
- rx.callout(
277
- message,
278
- icon="triangle-alert",
279
- color_scheme="red",
280
- max_width="90%",
281
- size="1",
282
- padding="0.5em",
283
- border_radius="9px",
284
- margin_top="18px",
406
+ rx.vstack(
407
+ rx.callout(
408
+ message.text,
409
+ icon="triangle-alert",
410
+ color_scheme="red",
411
+ max_width="100%",
412
+ size="1",
413
+ padding="0.5em",
414
+ border_radius="9px",
415
+ margin_top="18px",
416
+ ),
417
+ MessageActionsBar.render(message),
418
+ width="90%",
419
+ spacing="2",
285
420
  ),
286
421
  style=message_styles,
287
422
  )
@@ -328,7 +463,7 @@ class MessageComponent:
328
463
  ),
329
464
  (
330
465
  MessageType.ERROR,
331
- MessageComponent.error_message(message.text),
466
+ MessageComponent.error_message(message),
332
467
  ),
333
468
  (
334
469
  MessageType.SYSTEM,
@@ -14,6 +14,7 @@ import json
14
14
  import logging
15
15
  import uuid
16
16
  from collections.abc import AsyncGenerator
17
+ from datetime import UTC, datetime
17
18
  from typing import Any
18
19
 
19
20
  import reflex as rx
@@ -74,6 +75,10 @@ class ThreadState(rx.State):
74
75
  # File upload state
75
76
  uploaded_files: list[UploadedFile] = []
76
77
 
78
+ # Editing state
79
+ editing_message_id: str | None = None
80
+ edited_message_content: str = ""
81
+
77
82
  # Internal logic helper (not reactive)
78
83
  @property
79
84
  def _thread_service(self) -> ThreadService:
@@ -510,6 +515,67 @@ class ThreadState(rx.State):
510
515
  # Message processing
511
516
  # -------------------------------------------------------------------------
512
517
 
518
+ @rx.event
519
+ def set_editing_mode(self, message_id: str, content: str) -> None:
520
+ """Enable editing mode for a message."""
521
+ self.editing_message_id = message_id
522
+ self.edited_message_content = content
523
+
524
+ @rx.event
525
+ def set_edited_message_content(self, content: str) -> None:
526
+ """Set the content of the message currently being edited."""
527
+ self.edited_message_content = content
528
+
529
+ @rx.event
530
+ def cancel_edit(self) -> None:
531
+ """Cancel editing mode."""
532
+ self.editing_message_id = None
533
+ self.edited_message_content = ""
534
+
535
+ @rx.event(background=True)
536
+ async def submit_edited_message(self) -> AsyncGenerator[Any, Any]:
537
+ """Submit edited message."""
538
+ async with self:
539
+ content = self.edited_message_content.strip()
540
+ if len(content) < 1:
541
+ yield rx.toast.error(
542
+ "Nachricht darf nicht leer sein", position="top-right"
543
+ )
544
+ return
545
+
546
+ # Find message index
547
+ msg_index = -1
548
+ for i, m in enumerate(self.messages):
549
+ if m.id == self.editing_message_id:
550
+ msg_index = i
551
+ break
552
+
553
+ if msg_index == -1:
554
+ self.cancel_edit()
555
+ return
556
+
557
+ target_message = self.messages[msg_index]
558
+
559
+ # Update message
560
+ target_message.original_text = (
561
+ target_message.original_text or target_message.text
562
+ )
563
+ target_message.text = content
564
+
565
+ # Remove all messages AFTER this one
566
+ self.messages = self.messages[: msg_index + 1]
567
+
568
+ # Set prompt to bypass empty check in _begin_message_processing
569
+ self.prompt = content
570
+ self._skip_user_message = True
571
+
572
+ # Clear edit state
573
+ self.editing_message_id = None
574
+ self.edited_message_content = ""
575
+
576
+ # Trigger processing
577
+ await self._process_message()
578
+
513
579
  @rx.event(background=True)
514
580
  async def submit_message(self) -> AsyncGenerator[Any, Any]:
515
581
  """Submit a message and process the response."""
@@ -524,6 +590,76 @@ class ThreadState(rx.State):
524
590
  }
525
591
  """)
526
592
 
593
+ @rx.event(background=True)
594
+ async def delete_message(self, message_id: str) -> None:
595
+ """Delete a message from the conversation."""
596
+ async with self:
597
+ self.messages = [m for m in self.messages if m.id != message_id]
598
+ self._thread.messages = self.messages
599
+
600
+ if self._thread.state != ThreadStatus.NEW:
601
+ await self._thread_service.save_thread(
602
+ self._thread, self.current_user_id
603
+ )
604
+
605
+ @rx.event
606
+ def copy_message(self, text: str) -> list[Any]:
607
+ """Copy message text to clipboard."""
608
+ return [
609
+ rx.set_clipboard(text),
610
+ rx.toast.success("Nachricht kopiert"),
611
+ ]
612
+
613
+ @rx.event
614
+ def download_message(self, text: str, message_id: str) -> Any:
615
+ """Download message as markdown file."""
616
+ timestamp = datetime.now(UTC).strftime("%Y%m%d_%H%M%S")
617
+ filename = (
618
+ f"message_{message_id}_{timestamp}.md"
619
+ if message_id
620
+ else f"message_{timestamp}.md"
621
+ )
622
+
623
+ # Use JavaScript to trigger download
624
+ return rx.call_script(f"""
625
+ const blob = new Blob([{json.dumps(text)}], {{type: 'text/markdown'}});
626
+ const url = URL.createObjectURL(blob);
627
+ const a = document.createElement('a');
628
+ a.href = url;
629
+ a.download = '{filename}';
630
+ document.body.appendChild(a);
631
+ a.click();
632
+ document.body.removeChild(a);
633
+ URL.revokeObjectURL(url);
634
+ """)
635
+
636
+ @rx.event(background=True)
637
+ async def retry_message(self, message_id: str) -> None:
638
+ """Retry generating a message."""
639
+ async with self:
640
+ # Find message index
641
+ index = -1
642
+ for i, msg in enumerate(self.messages):
643
+ if msg.id == message_id:
644
+ index = i
645
+ break
646
+
647
+ if index == -1:
648
+ return
649
+
650
+ # Keep context up to this message
651
+ # effectively removing this message and everything after
652
+ self.messages = self.messages[:index]
653
+
654
+ # Set prompt to bypass check (content checks)
655
+ self.prompt = "Regenerate"
656
+
657
+ # Flag to skip adding a new user message
658
+ self._skip_user_message = True
659
+
660
+ # Trigger processing directly
661
+ await self._process_message()
662
+
527
663
  async def _process_message(self) -> None:
528
664
  """Process the current message and stream the response."""
529
665
  logger.debug("Processing message: %s", self.prompt)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: appkit-assistant
3
- Version: 0.17.0
3
+ Version: 0.17.1
4
4
  Summary: Add your description here
5
5
  Project-URL: Homepage, https://github.com/jenreh/appkit
6
6
  Project-URL: Documentation, https://github.com/jenreh/appkit/tree/main/docs
@@ -3,18 +3,18 @@ appkit_assistant/pages.py,sha256=gDvBweUO2WjrhP1RE5AAkjL1_S-givWr3CkkGZKws_E,471
3
3
  appkit_assistant/backend/file_manager.py,sha256=54SYphu6FsxbEYuMx8ohQiSAeY2gGDV1q3S6RZuNku0,3153
4
4
  appkit_assistant/backend/mcp_auth_service.py,sha256=lYQEe4yOZ48ear6dvcuOXsaOc6RClIBMsOOkV7SG5Aw,27768
5
5
  appkit_assistant/backend/model_manager.py,sha256=fmv3yP63LxDnne4vjT7IzETTI2aSxViC2FSUfHQajlk,4382
6
- appkit_assistant/backend/models.py,sha256=vymgJ7npF-L-4WGXWwVUdHqLo3MAypPPaaD_SyDcAIw,8198
6
+ appkit_assistant/backend/models.py,sha256=GCFWUUPsVspcFEv9naQ8n2bMU8FzMNrmqm3VgW1Fqfw,8346
7
7
  appkit_assistant/backend/processor.py,sha256=LtkkC6v0idNtbuMm3Sw5J9zIjYqtNhtxYxjYefPSS9A,2135
8
8
  appkit_assistant/backend/repositories.py,sha256=R-7kYdxg4RWQrTEOU4tbcOEhJA_FlesWrt65UpItRSU,5547
9
- appkit_assistant/backend/response_accumulator.py,sha256=dFJZiXcDn4V2POSk7Us6gQLsrUIRBMLdoOP61LwutdI,9766
9
+ appkit_assistant/backend/response_accumulator.py,sha256=BCK-Ut_Wmo7rhEqOb7QlqXO8TrtANjL80FbX_AvMl1Q,10056
10
10
  appkit_assistant/backend/system_prompt_cache.py,sha256=83OIyixeTb3HKOy3XIzPyTAE-G2JyqrfcG8xVeTS2Ls,5514
11
11
  appkit_assistant/backend/processors/claude_base.py,sha256=j0DhBn8EVAjW_bfCghXaEHyORO1raUNdQeemVWCKJlA,5376
12
12
  appkit_assistant/backend/processors/claude_responses_processor.py,sha256=_quuN5FRsPSpQjaNIceN-Z66Fb3RnhXtcsS4gE0NrPA,32980
13
13
  appkit_assistant/backend/processors/gemini_base.py,sha256=ijCa8-_xdddD6ms_pkUjCj5kHZOoQ1wfw-7AhhXu6vo,2286
14
- appkit_assistant/backend/processors/gemini_responses_processor.py,sha256=pzbczuw7MsoABdkuJGNxlebV8POA2D72XMzLoMhj9k4,26429
14
+ appkit_assistant/backend/processors/gemini_responses_processor.py,sha256=V5jZ83a3vi60aFTtRnbwP2q1PyEGw1iB6dYne-4CgI4,26484
15
15
  appkit_assistant/backend/processors/lorem_ipsum_processor.py,sha256=WR4s1RyOi5xgWVpre04xoxoMLIAINkpdvRCkSfNuoMc,4699
16
16
  appkit_assistant/backend/processors/openai_base.py,sha256=TBQCZW7RxaPMag_DX_tpLyMpZ_PZ_KiO8_sFN49OCpk,4424
17
- appkit_assistant/backend/processors/openai_chat_completion_processor.py,sha256=nTxouoXDU6VcQr8UhA2KiMNt60KvIwM8cH9Z8lo4dXY,4218
17
+ appkit_assistant/backend/processors/openai_chat_completion_processor.py,sha256=XFp_V9Yp4KcTmicbCe3fl_3G2tP5Ffm-xLVqW50HyQw,4629
18
18
  appkit_assistant/backend/processors/openai_responses_processor.py,sha256=hysK7mlsG2t8SfltQpCvKA6MxpeIomRMGX-tSMaUshc,29492
19
19
  appkit_assistant/backend/processors/perplexity_processor.py,sha256=weHukv78MSCF_uSCKGSMpNYHsET9OB8IhpvUiMfPQ8A,3355
20
20
  appkit_assistant/backend/services/thread_service.py,sha256=LpM8ZZHt1o4MYEKzH_XPURSi3qS6p3pAQA53tOE53MU,4663
@@ -24,7 +24,7 @@ appkit_assistant/components/composer_key_handler.py,sha256=KyZYyhxzFR8DH_7F_DrvT
24
24
  appkit_assistant/components/mcp_oauth.py,sha256=puLwxAhmF25BjnZMdJbKIfC6bFXK2D8LybOX0kD7Ri4,1737
25
25
  appkit_assistant/components/mcp_server_dialogs.py,sha256=afIImmhfrNyLmxDZBpCxHxvD8HKpDanIloLEC8dJgro,23444
26
26
  appkit_assistant/components/mcp_server_table.py,sha256=1dziN7hDDvE8Y3XcdIs0wUPv1H64kP9gRAEjgH9Yvzo,2323
27
- appkit_assistant/components/message.py,sha256=xFMcrSMErHbbgZGl0rujNwhL7nRGwIp-S-a47cYwaJ4,14605
27
+ appkit_assistant/components/message.py,sha256=SJcwWfSw5XxiSHtKirJUun9jkx3-ATpZ0AHLv82KwXc,19824
28
28
  appkit_assistant/components/system_prompt_editor.py,sha256=REl33zFmcpYRe9kxvFrBRYg40dV4L4FtVC_3ibLsmrU,2940
29
29
  appkit_assistant/components/thread.py,sha256=-KK1vcEmITR_oDGLbQhIa2WxRCVxEqel12m4haS7y9w,8461
30
30
  appkit_assistant/components/threadlist.py,sha256=1xVakSTQYi5-wgED3fTJVggeIjL_fkthehce0wKUYtM,4896
@@ -33,7 +33,7 @@ appkit_assistant/state/mcp_oauth_state.py,sha256=6MofExrbOOEl_YUcUOqcSTN3h7KAaER
33
33
  appkit_assistant/state/mcp_server_state.py,sha256=3AFvy53xx_eLTxw-LfJklPTgq4Ohqu4xs1QlLs-kU4U,11387
34
34
  appkit_assistant/state/system_prompt_state.py,sha256=zdnYrTnl7EszALRiodu6pcuQUd2tmtPG1eJ10j_OotI,7705
35
35
  appkit_assistant/state/thread_list_state.py,sha256=DEOR5Nklj1qfYaxSRMXCZdZRv2iq2Jb37JSg739_wL4,10250
36
- appkit_assistant/state/thread_state.py,sha256=xLydHA5YDFj3J1fGBQoAZsWg3zlcKOh2-9SzvlGvyU0,34742
37
- appkit_assistant-0.17.0.dist-info/METADATA,sha256=jzEwclPQN3VXn5APgK9EQMLiGKnug-wI-JRxPu44Kao,9498
38
- appkit_assistant-0.17.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
39
- appkit_assistant-0.17.0.dist-info/RECORD,,
36
+ appkit_assistant/state/thread_state.py,sha256=Hz7vRsBJ2cTV_xENuMoZBVSo2FGbR4uovdwiXF1zixk,39292
37
+ appkit_assistant-0.17.1.dist-info/METADATA,sha256=t0hdCrMbCpvbETpblS3bmLtJ0ltfMXhGI9MTOtnrzII,9498
38
+ appkit_assistant-0.17.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
39
+ appkit_assistant-0.17.1.dist-info/RECORD,,