vibecore 0.3.0b2__py3-none-any.whl → 0.3.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.

Potentially problematic release.


This version of vibecore might be problematic. Click here for more details.

vibecore/settings.py CHANGED
@@ -155,6 +155,11 @@ class Settings(BaseSettings):
155
155
  description="List of MCP servers to connect to",
156
156
  )
157
157
 
158
+ rich_tool_names: list[str] = Field(
159
+ default_factory=list,
160
+ description="List of tools to render with RichToolMessage (temporary settings)",
161
+ )
162
+
158
163
  @property
159
164
  def model(self) -> str | Model:
160
165
  """Get the configured model.
@@ -9,12 +9,14 @@ import contextlib
9
9
  import json
10
10
  from typing import Any
11
11
 
12
+ from vibecore.settings import settings
12
13
  from vibecore.widgets.messages import MessageStatus
13
14
  from vibecore.widgets.tool_messages import (
14
15
  BaseToolMessage,
15
16
  MCPToolMessage,
16
17
  PythonToolMessage,
17
18
  ReadToolMessage,
19
+ RichToolMessage,
18
20
  TaskToolMessage,
19
21
  TodoWriteToolMessage,
20
22
  ToolMessage,
@@ -129,6 +131,12 @@ def create_tool_message(
129
131
  else:
130
132
  return WebFetchToolMessage(url=url, status=status)
131
133
 
134
+ elif tool_name in settings.rich_tool_names:
135
+ if output is not None:
136
+ return RichToolMessage(tool_name=tool_name, arguments=arguments, output=output, status=status)
137
+ else:
138
+ return RichToolMessage(tool_name=tool_name, arguments=arguments, status=status)
139
+
132
140
  # Default to generic ToolMessage for all other tools
133
141
  else:
134
142
  if output is not None:
@@ -483,6 +483,118 @@ class MCPToolMessage(BaseToolMessage):
483
483
  )
484
484
 
485
485
 
486
+ class RichToolMessage(BaseToolMessage):
487
+ """A widget to display rich (json/markdown) custom tool execution messages."""
488
+
489
+ SQL_QUERY_KEY = "query"
490
+ tool_name: reactive[str] = reactive("")
491
+ arguments: reactive[str] = reactive("")
492
+
493
+ def __init__(
494
+ self,
495
+ tool_name: str,
496
+ arguments: str,
497
+ output: str = "",
498
+ status: MessageStatus = MessageStatus.EXECUTING,
499
+ **kwargs,
500
+ ) -> None:
501
+ """
502
+ Construct an RichToolMessage.
503
+
504
+ Args:
505
+ tool_name: The name of the tool being called.
506
+ arguments: JSON string of tool arguments.
507
+ output: The output from the tool (optional, can be set later).
508
+ status: The status of execution.
509
+ **kwargs: Additional keyword arguments for Widget.
510
+ """
511
+ super().__init__(status=status, **kwargs)
512
+ self.tool_name = tool_name
513
+ self.arguments = arguments
514
+ self.output = output
515
+
516
+ def _prettify_json_output(self, output: str) -> tuple[bool, str]:
517
+ """Try to prettify JSON output.
518
+
519
+ Args:
520
+ output: The raw output string.
521
+
522
+ Returns:
523
+ A tuple of (is_json, formatted_output).
524
+ """
525
+ if not output or not output.strip():
526
+ return False, output
527
+
528
+ try:
529
+ # Try to parse as JSON
530
+ json_obj = json.loads(output)
531
+ # Pretty print with 2-space indentation
532
+ formatted = json.dumps(json_obj, indent=2, ensure_ascii=False)
533
+ return True, formatted
534
+ except (json.JSONDecodeError, TypeError, ValueError):
535
+ # Not valid JSON, return as-is
536
+ return False, output
537
+
538
+ def on_button_pressed(self, event: Button.Pressed) -> None:
539
+ """Handle button press events."""
540
+ if event.button.has_class("copy-button"):
541
+ arg_dict = json.loads(self.arguments)
542
+ if self.SQL_QUERY_KEY in arg_dict:
543
+ # XXX(serialx): Special case for SQL queries
544
+ query = arg_dict[self.SQL_QUERY_KEY]
545
+ self.app.copy_to_clipboard(query)
546
+
547
+ def compose(self) -> ComposeResult:
548
+ """Create child widgets for the rich tool message."""
549
+ # Header line showing MCP server and tool
550
+ # Access the actual values, not the reactive descriptors
551
+ yield MessageHeader("⏺", self.tool_name, status=self.status)
552
+
553
+ # Arguments display (if any)
554
+ if self.arguments and self.arguments != "{}":
555
+ with Horizontal(classes="rich-arguments"):
556
+ yield Static("└─", classes="rich-arguments-prefix")
557
+ with Vertical(classes="rich-arguments-content"):
558
+ # Truncate arguments if too long
559
+ max_args_length = 100
560
+ arg_dict = json.loads(self.arguments)
561
+ if self.SQL_QUERY_KEY in arg_dict:
562
+ # XXX(serialx): Special case for SQL queries
563
+ query = arg_dict[self.SQL_QUERY_KEY]
564
+ yield Button("Copy", classes="copy-button", variant="primary")
565
+ yield ExpandableMarkdown(query, language="sql", truncated_lines=8, classes="rich-output-sql")
566
+ del arg_dict[self.SQL_QUERY_KEY]
567
+
568
+ display_args = arg_dict[:max_args_length] + "…" if len(arg_dict) > max_args_length else arg_dict
569
+ yield Static(f"Args: {display_args}", classes="rich-arguments-text")
570
+
571
+ # Output - check if it's JSON and prettify if so
572
+ if self.output:
573
+ try:
574
+ json_output = json.loads(self.output)
575
+ except json.JSONDecodeError:
576
+ json_output = None
577
+ if json_output:
578
+ assert json_output.get("type") == "text", "Expected JSON output type to be 'text'"
579
+ is_json, processed_output = self._prettify_json_output(json_output.get("text", ""))
580
+ else:
581
+ # output should always be a JSON string, but if not, treat it as plain text
582
+ is_json, processed_output = False, self.output
583
+ with Horizontal(classes="tool-output"):
584
+ yield Static("└─", classes="tool-output-prefix")
585
+ with Vertical(classes="tool-output-content"):
586
+ if is_json:
587
+ # Use ExpandableMarkdown for JSON with syntax highlighting
588
+ yield ExpandableMarkdown(
589
+ processed_output, language="json", truncated_lines=8, classes="rich-output-json"
590
+ )
591
+ else:
592
+ # Use ExpandableMarkdown for non-JSON content (renders as markdown without code block)
593
+ yield ExpandableMarkdown(
594
+ processed_output, language="", truncated_lines=5, classes="rich-output-markdown"
595
+ )
596
+
597
+
486
598
  class WebSearchToolMessage(BaseToolMessage):
487
599
  """A widget to display web search results."""
488
600
 
@@ -288,6 +288,75 @@ MCPToolMessage {
288
288
  }
289
289
  }
290
290
 
291
+ RichToolMessage {
292
+ Horizontal.rich-arguments {
293
+ height: auto;
294
+ layers: main button;
295
+
296
+ .copy-button {
297
+ layer: button;
298
+ dock: right;
299
+ height: 1;
300
+ width: 8;
301
+ min-width: 8;
302
+ margin: 0;
303
+ padding: 0;
304
+ background: $secondary;
305
+ color: $text;
306
+ border: none;
307
+
308
+ &:hover {
309
+ background: $secondary-lighten-1;
310
+ }
311
+
312
+ &:focus {
313
+ background: $secondary-lighten-1;
314
+ text-style: bold;
315
+ }
316
+ }
317
+
318
+ &> .rich-arguments-prefix {
319
+ height: 1;
320
+ width: 5;
321
+ padding-left: 2;
322
+ padding-right: 1;
323
+ color: $text-muted;
324
+ }
325
+
326
+ &> Vertical.rich-arguments-content {
327
+ height: auto;
328
+ width: 1fr;
329
+
330
+ .rich-arguments-label {
331
+ color: $text-muted;
332
+ # margin-bottom: 1;
333
+ }
334
+
335
+ .rich-arguments-text {
336
+ color: $text-muted;
337
+ text-overflow: ellipsis;
338
+ }
339
+ }
340
+ }
341
+
342
+ Horizontal.tool-output {
343
+ height: auto;
344
+
345
+ &> .tool-output-prefix {
346
+ height: 1;
347
+ width: 5;
348
+ padding-left: 2;
349
+ padding-right: 1;
350
+ color: $text-muted;
351
+ }
352
+
353
+ &> Vertical.tool-output-content {
354
+ height: auto;
355
+ width: 1fr;
356
+ }
357
+ }
358
+ }
359
+
291
360
  WebSearchToolMessage {
292
361
  Horizontal.tool-output {
293
362
  height: auto;
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: vibecore
3
- Version: 0.3.0b2
3
+ Version: 0.3.1
4
4
  Summary: Build your own AI-powered automation tools in the terminal with this extensible agent framework
5
5
  Project-URL: Homepage, https://github.com/serialx/vibecore
6
6
  Project-URL: Repository, https://github.com/serialx/vibecore
@@ -5,7 +5,7 @@ vibecore/flow.py,sha256=ZaKzMsz4YBvgelVzJOIHnTJzMWTmvkfvudwW_hllq6U,3384
5
5
  vibecore/main.py,sha256=MIn7Mpg_xO_20c6Mju8PgY-MmVCTER9cepHd5YFbtYs,20175
6
6
  vibecore/main.tcss,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
7
  vibecore/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
- vibecore/settings.py,sha256=OnEME61vi7qBiSbu7Q_7twAZa7l0sOXBIavxYNAVOWU,6897
8
+ vibecore/settings.py,sha256=PwivzoJ-xyJu-Mmnv4E6G_E8up4GNvvz9_j4ttj-GUw,7063
9
9
  vibecore/agents/default.py,sha256=wxeP3Hsq9MVBChyMF_sNkVHCtFFXgy5ghDIxy9eH_fQ,2287
10
10
  vibecore/agents/prompts.py,sha256=0oO9QzcytIbzgZcKJQjWD9fSRNQqBqqK5ku0fcYZZrA,324
11
11
  vibecore/agents/task.py,sha256=cdhZDzKDA8eHHNYPhogFIKBms3oVAMvYeiBB2GqYNuE,1898
@@ -75,11 +75,11 @@ vibecore/widgets/info.py,sha256=hXtsRUOE13oHbIm9FNe1GCUX_FCht28pgT9SQWeJ69I,1567
75
75
  vibecore/widgets/info.tcss,sha256=v30IqNt1two-ezIcm18ZEInKRKcRkAW-h-UH2r8QzSo,201
76
76
  vibecore/widgets/messages.py,sha256=az4fJtdk3ItSoFZBG_adRDUHdTLttIV8F23E8LOb-mg,8156
77
77
  vibecore/widgets/messages.tcss,sha256=WtBbjf5LgFkUhzhVlxJB7NMbagWladJawDizvDm7hBE,1271
78
- vibecore/widgets/tool_message_factory.py,sha256=FMwavKMRNT8ik9RgcL37WuM19Ln-c5wuFmS0A2CkikM,5377
79
- vibecore/widgets/tool_messages.py,sha256=PKmPigeOlccowo0uLpgIPzsmmE-zkichzuXIS6hWsbQ,24501
80
- vibecore/widgets/tool_messages.tcss,sha256=mcFY58FE1AcfEvEiA_Yb7sMpIniTIC_IjDvv8M7vWOA,6924
81
- vibecore-0.3.0b2.dist-info/METADATA,sha256=7YQejvTynr_4g3MmrV0cRLHdH4P5OiqC403t8qYjVnM,18095
82
- vibecore-0.3.0b2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
83
- vibecore-0.3.0b2.dist-info/entry_points.txt,sha256=i9mOKvpz07ciV_YYisxNCYZ53_Crjkn9mciiQ3aA6QM,51
84
- vibecore-0.3.0b2.dist-info/licenses/LICENSE,sha256=KXxxifvrcreHrZ4aOYgP-vA8DRHHueW389KKOeEbtjc,1069
85
- vibecore-0.3.0b2.dist-info/RECORD,,
78
+ vibecore/widgets/tool_message_factory.py,sha256=yrZorT4HKo5b6rWUc0dgQle7q7cvLyq8JllE772RZS0,5730
79
+ vibecore/widgets/tool_messages.py,sha256=hJOolN3iLTAjqfotfH1elXqsdDo1r_UHjsyRVH0GAeo,29415
80
+ vibecore/widgets/tool_messages.tcss,sha256=gdChmHClURqn_sD9GkcOGQcQVYvUUl75mLUYp85sKz8,8442
81
+ vibecore-0.3.1.dist-info/METADATA,sha256=wCQB7NKn35T0W3onSrpV1FNX13zHzO-VEn0WqU6ZIlw,18093
82
+ vibecore-0.3.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
83
+ vibecore-0.3.1.dist-info/entry_points.txt,sha256=i9mOKvpz07ciV_YYisxNCYZ53_Crjkn9mciiQ3aA6QM,51
84
+ vibecore-0.3.1.dist-info/licenses/LICENSE,sha256=KXxxifvrcreHrZ4aOYgP-vA8DRHHueW389KKOeEbtjc,1069
85
+ vibecore-0.3.1.dist-info/RECORD,,