yera 0.1.0__py3-none-any.whl → 0.2.0__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.
Files changed (192) hide show
  1. infra_mvp/base_client.py +29 -0
  2. infra_mvp/base_server.py +68 -0
  3. infra_mvp/monitoring/__init__.py +15 -0
  4. infra_mvp/monitoring/metrics.py +185 -0
  5. infra_mvp/stream/README.md +56 -0
  6. infra_mvp/stream/__init__.py +14 -0
  7. infra_mvp/stream/__main__.py +101 -0
  8. infra_mvp/stream/agents/demos/financial/chart_additions_plan.md +170 -0
  9. infra_mvp/stream/agents/demos/financial/portfolio_assistant_stream.json +1571 -0
  10. infra_mvp/stream/agents/reference/blocks/action.json +170 -0
  11. infra_mvp/stream/agents/reference/blocks/button.json +66 -0
  12. infra_mvp/stream/agents/reference/blocks/date.json +65 -0
  13. infra_mvp/stream/agents/reference/blocks/input_prompt.json +94 -0
  14. infra_mvp/stream/agents/reference/blocks/layout.json +288 -0
  15. infra_mvp/stream/agents/reference/blocks/markdown.json +344 -0
  16. infra_mvp/stream/agents/reference/blocks/slider.json +67 -0
  17. infra_mvp/stream/agents/reference/blocks/spinner.json +110 -0
  18. infra_mvp/stream/agents/reference/blocks/table.json +56 -0
  19. infra_mvp/stream/agents/reference/chat_dynamics/branching_test_stream.json +145 -0
  20. infra_mvp/stream/app.py +49 -0
  21. infra_mvp/stream/container.py +112 -0
  22. infra_mvp/stream/schemas/__init__.py +16 -0
  23. infra_mvp/stream/schemas/agent.py +24 -0
  24. infra_mvp/stream/schemas/interaction.py +28 -0
  25. infra_mvp/stream/schemas/session.py +30 -0
  26. infra_mvp/stream/server.py +321 -0
  27. infra_mvp/stream/services/__init__.py +12 -0
  28. infra_mvp/stream/services/agent_service.py +40 -0
  29. infra_mvp/stream/services/event_converter.py +83 -0
  30. infra_mvp/stream/services/session_service.py +247 -0
  31. yera/__init__.py +50 -1
  32. yera/agents/__init__.py +2 -0
  33. yera/agents/context.py +41 -0
  34. yera/agents/dataclasses.py +69 -0
  35. yera/agents/decorator.py +207 -0
  36. yera/agents/discovery.py +124 -0
  37. yera/agents/typing/__init__.py +0 -0
  38. yera/agents/typing/coerce.py +408 -0
  39. yera/agents/typing/utils.py +19 -0
  40. yera/agents/typing/validate.py +206 -0
  41. yera/cli.py +377 -0
  42. yera/config/__init__.py +1 -0
  43. yera/config/config_utils.py +164 -0
  44. yera/config/function_config.py +55 -0
  45. yera/config/logging.py +18 -0
  46. yera/config/tool_config.py +8 -0
  47. yera/config2/__init__.py +8 -0
  48. yera/config2/dataclasses.py +534 -0
  49. yera/config2/keyring.py +270 -0
  50. yera/config2/paths.py +28 -0
  51. yera/config2/read.py +113 -0
  52. yera/config2/setup.py +109 -0
  53. yera/config2/setup_handlers/__init__.py +1 -0
  54. yera/config2/setup_handlers/anthropic.py +126 -0
  55. yera/config2/setup_handlers/azure.py +236 -0
  56. yera/config2/setup_handlers/base.py +125 -0
  57. yera/config2/setup_handlers/llama_cpp.py +205 -0
  58. yera/config2/setup_handlers/ollama.py +157 -0
  59. yera/config2/setup_handlers/openai.py +137 -0
  60. yera/config2/write.py +87 -0
  61. yera/dsl/__init__.py +0 -0
  62. yera/dsl/functions.py +94 -0
  63. yera/dsl/struct.py +20 -0
  64. yera/dsl/workspace.py +79 -0
  65. yera/events/__init__.py +57 -0
  66. yera/events/blocks/__init__.py +68 -0
  67. yera/events/blocks/action.py +57 -0
  68. yera/events/blocks/bar_chart.py +92 -0
  69. yera/events/blocks/base/__init__.py +20 -0
  70. yera/events/blocks/base/base.py +166 -0
  71. yera/events/blocks/base/chart.py +288 -0
  72. yera/events/blocks/base/layout.py +111 -0
  73. yera/events/blocks/buttons.py +37 -0
  74. yera/events/blocks/columns.py +26 -0
  75. yera/events/blocks/container.py +24 -0
  76. yera/events/blocks/date_picker.py +50 -0
  77. yera/events/blocks/exit.py +39 -0
  78. yera/events/blocks/form.py +24 -0
  79. yera/events/blocks/input_echo.py +22 -0
  80. yera/events/blocks/input_request.py +31 -0
  81. yera/events/blocks/line_chart.py +97 -0
  82. yera/events/blocks/markdown.py +67 -0
  83. yera/events/blocks/slider.py +54 -0
  84. yera/events/blocks/spinner.py +55 -0
  85. yera/events/blocks/system_prompt.py +22 -0
  86. yera/events/blocks/table.py +291 -0
  87. yera/events/models/__init__.py +39 -0
  88. yera/events/models/block_data.py +112 -0
  89. yera/events/models/in_event.py +7 -0
  90. yera/events/models/out_event.py +75 -0
  91. yera/events/runtime.py +187 -0
  92. yera/events/stream.py +91 -0
  93. yera/models/__init__.py +0 -0
  94. yera/models/data_classes.py +20 -0
  95. yera/models/llm_atlas_proxy.py +44 -0
  96. yera/models/llm_context.py +99 -0
  97. yera/models/llm_interfaces/__init__.py +0 -0
  98. yera/models/llm_interfaces/anthropic.py +153 -0
  99. yera/models/llm_interfaces/aws_bedrock.py +14 -0
  100. yera/models/llm_interfaces/azure_openai.py +143 -0
  101. yera/models/llm_interfaces/base.py +26 -0
  102. yera/models/llm_interfaces/interface_registry.py +74 -0
  103. yera/models/llm_interfaces/llama_cpp.py +136 -0
  104. yera/models/llm_interfaces/mock.py +29 -0
  105. yera/models/llm_interfaces/ollama_interface.py +118 -0
  106. yera/models/llm_interfaces/open_ai.py +150 -0
  107. yera/models/llm_workspace.py +19 -0
  108. yera/models/model_atlas.py +139 -0
  109. yera/models/model_definition.py +38 -0
  110. yera/models/model_factory.py +33 -0
  111. yera/opaque/__init__.py +9 -0
  112. yera/opaque/base.py +20 -0
  113. yera/opaque/decorator.py +8 -0
  114. yera/opaque/markdown.py +57 -0
  115. yera/opaque/opaque_function.py +25 -0
  116. yera/tools/__init__.py +29 -0
  117. yera/tools/atlas_tool.py +20 -0
  118. yera/tools/base.py +24 -0
  119. yera/tools/decorated_tool.py +18 -0
  120. yera/tools/decorator.py +35 -0
  121. yera/tools/tool_atlas.py +51 -0
  122. yera/tools/tool_utils.py +361 -0
  123. yera/ui/dist/404.html +1 -0
  124. yera/ui/dist/__next.__PAGE__.txt +10 -0
  125. yera/ui/dist/__next._full.txt +23 -0
  126. yera/ui/dist/__next._head.txt +6 -0
  127. yera/ui/dist/__next._index.txt +5 -0
  128. yera/ui/dist/__next._tree.txt +7 -0
  129. yera/ui/dist/_next/static/chunks/4c4688e1ff21ad98.js +1 -0
  130. yera/ui/dist/_next/static/chunks/652cd53c27924d50.js +4 -0
  131. yera/ui/dist/_next/static/chunks/786d2107b51e8499.css +1 -0
  132. yera/ui/dist/_next/static/chunks/7de9141b1af425c3.js +1 -0
  133. yera/ui/dist/_next/static/chunks/87ef65064d3524c1.js +2 -0
  134. yera/ui/dist/_next/static/chunks/a6dad97d9634a72d.js +1 -0
  135. yera/ui/dist/_next/static/chunks/a6dad97d9634a72d.js.map +1 -0
  136. yera/ui/dist/_next/static/chunks/c4c79d5d0b280aeb.js +1 -0
  137. yera/ui/dist/_next/static/chunks/dc2d2a247505d66f.css +5 -0
  138. yera/ui/dist/_next/static/chunks/f773f714b55ec620.js +37 -0
  139. yera/ui/dist/_next/static/chunks/turbopack-98b3031e1b1dbc33.js +4 -0
  140. yera/ui/dist/_next/static/lnhYLzJ1-a5EfNbW1uFF6/_buildManifest.js +11 -0
  141. yera/ui/dist/_next/static/lnhYLzJ1-a5EfNbW1uFF6/_clientMiddlewareManifest.json +1 -0
  142. yera/ui/dist/_next/static/lnhYLzJ1-a5EfNbW1uFF6/_ssgManifest.js +1 -0
  143. yera/ui/dist/_next/static/media/14e23f9b59180572-s.9c448f3c.woff2 +0 -0
  144. yera/ui/dist/_next/static/media/2a65768255d6b625-s.p.d19752fb.woff2 +0 -0
  145. yera/ui/dist/_next/static/media/2b2eb4836d2dad95-s.f36de3af.woff2 +0 -0
  146. yera/ui/dist/_next/static/media/31183d9fd602dc89-s.c4ff9b73.woff2 +0 -0
  147. yera/ui/dist/_next/static/media/3fcb63a1ac6a562e-s.2f77a576.woff2 +0 -0
  148. yera/ui/dist/_next/static/media/45ec8de98929b0f6-s.81056204.woff2 +0 -0
  149. yera/ui/dist/_next/static/media/4fa387ec64143e14-s.c1fdd6c2.woff2 +0 -0
  150. yera/ui/dist/_next/static/media/65c558afe41e89d6-s.e2c8389a.woff2 +0 -0
  151. yera/ui/dist/_next/static/media/67add6cc0f54b8cf-s.8ce53448.woff2 +0 -0
  152. yera/ui/dist/_next/static/media/7178b3e590c64307-s.b97b3418.woff2 +0 -0
  153. yera/ui/dist/_next/static/media/797e433ab948586e-s.p.dbea232f.woff2 +0 -0
  154. yera/ui/dist/_next/static/media/8a480f0b521d4e75-s.8e0177b5.woff2 +0 -0
  155. yera/ui/dist/_next/static/media/a8ff2d5d0ccb0d12-s.fc5b72a7.woff2 +0 -0
  156. yera/ui/dist/_next/static/media/aae5f0be330e13db-s.p.853e26d6.woff2 +0 -0
  157. yera/ui/dist/_next/static/media/b11a6ccf4a3edec7-s.2113d282.woff2 +0 -0
  158. yera/ui/dist/_next/static/media/b49b0d9b851e4899-s.4f3fa681.woff2 +0 -0
  159. yera/ui/dist/_next/static/media/bbc41e54d2fcbd21-s.799d8ef8.woff2 +0 -0
  160. yera/ui/dist/_next/static/media/caa3a2e1cccd8315-s.p.853070df.woff2 +0 -0
  161. yera/ui/dist/_next/static/media/favicon.0b3bf435.ico +0 -0
  162. yera/ui/dist/_not-found/__next._full.txt +14 -0
  163. yera/ui/dist/_not-found/__next._head.txt +6 -0
  164. yera/ui/dist/_not-found/__next._index.txt +5 -0
  165. yera/ui/dist/_not-found/__next._not-found.__PAGE__.txt +5 -0
  166. yera/ui/dist/_not-found/__next._not-found.txt +4 -0
  167. yera/ui/dist/_not-found/__next._tree.txt +2 -0
  168. yera/ui/dist/_not-found.html +1 -0
  169. yera/ui/dist/_not-found.txt +14 -0
  170. yera/ui/dist/agent-icon.svg +3 -0
  171. yera/ui/dist/favicon.ico +0 -0
  172. yera/ui/dist/file.svg +1 -0
  173. yera/ui/dist/globe.svg +1 -0
  174. yera/ui/dist/index.html +1 -0
  175. yera/ui/dist/index.txt +23 -0
  176. yera/ui/dist/logo/full_logo.png +0 -0
  177. yera/ui/dist/logo/rune_logo.png +0 -0
  178. yera/ui/dist/logo/rune_logo_borderless.png +0 -0
  179. yera/ui/dist/logo/text_logo.png +0 -0
  180. yera/ui/dist/next.svg +1 -0
  181. yera/ui/dist/send.png +0 -0
  182. yera/ui/dist/send_single.png +0 -0
  183. yera/ui/dist/vercel.svg +1 -0
  184. yera/ui/dist/window.svg +1 -0
  185. yera/utils/__init__.py +1 -0
  186. yera/utils/path_utils.py +38 -0
  187. yera-0.2.0.dist-info/METADATA +65 -0
  188. yera-0.2.0.dist-info/RECORD +190 -0
  189. {yera-0.1.0.dist-info → yera-0.2.0.dist-info}/WHEEL +1 -1
  190. yera-0.2.0.dist-info/entry_points.txt +2 -0
  191. yera-0.1.0.dist-info/METADATA +0 -11
  192. yera-0.1.0.dist-info/RECORD +0 -4
@@ -0,0 +1,111 @@
1
+ """Shared layout block implementation."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from collections.abc import Callable
6
+ from contextvars import ContextVar, Token
7
+ from dataclasses import dataclass, field
8
+ from typing import Any
9
+
10
+ from yera.events.blocks.base.base import (
11
+ _StreamHandle,
12
+ create_event,
13
+ get_parent_block_id,
14
+ )
15
+ from yera.events.models import (
16
+ ColumnsData,
17
+ ContainerData,
18
+ LayoutEndData,
19
+ )
20
+ from yera.events.stream import await_input, push_output
21
+
22
+
23
+ @dataclass
24
+ class LayoutContext:
25
+ """Context for tracking active layout blocks."""
26
+
27
+ block_id: str
28
+ block_type: str # "container", "columns", or "form"
29
+ column_index: int = 0 # For columns, tracks current column index
30
+ input_count: int = (
31
+ 0 # Number of await_user blocks emitted in this layout; drained on exit
32
+ )
33
+ result_parsers: list[Callable[[str], Any]] = field(default_factory=list)
34
+
35
+
36
+ # Context variable to track the current layout
37
+ _current_layout: ContextVar[LayoutContext | None] = ContextVar(
38
+ "current_layout", default=None
39
+ )
40
+
41
+
42
+ class LayoutHandle(_StreamHandle):
43
+ """Stream handle for layout blocks (container, columns)."""
44
+
45
+ def __init__(
46
+ self,
47
+ block_id: str,
48
+ block_type: str,
49
+ data: ContainerData | ColumnsData,
50
+ ):
51
+ super().__init__(block_id, block_type)
52
+ self.data = data
53
+ self._token: Token[LayoutContext | None] | None = None
54
+
55
+ def __enter__(self):
56
+ # Get parent block ID before setting new layout context
57
+ parent_block_id = get_parent_block_id()
58
+
59
+ # Create layout context (keep reference so __exit__ can drain input_count)
60
+ layout_context = LayoutContext(
61
+ block_id=self.block_id, block_type=self.block_type
62
+ )
63
+ self._layout_context = layout_context
64
+ self._token = _current_layout.set(layout_context)
65
+
66
+ # Emit layout event with pre-built data from factory
67
+ event = self._create_chunk_event(
68
+ data=self.data,
69
+ message_type="layout",
70
+ parent_block_id=parent_block_id,
71
+ )
72
+ push_output(event)
73
+
74
+ return self
75
+
76
+ def __exit__(self, exc_type, exc_value, traceback):
77
+ # Clear layout context
78
+ if self._token is not None:
79
+ _current_layout.reset(self._token)
80
+ # Emit layout_end so the stream can pause after all layout children have been sent
81
+ layout_end_event = create_event(
82
+ block_type="layout_end",
83
+ block_id=self.block_id,
84
+ data=LayoutEndData(),
85
+ message_type="informational",
86
+ chunk_id=1,
87
+ )
88
+ push_output(layout_end_event)
89
+ # For container/columns, drain inputs so the agent does not block. Form drains in result().
90
+ if self.block_type != "form":
91
+ for _ in range(self._layout_context.input_count):
92
+ await_input()
93
+ return False
94
+
95
+ def result(self) -> tuple[Any, ...]:
96
+ """Return parsed form values. Only supported for form blocks."""
97
+ if self.block_type != "form":
98
+ raise TypeError("result() is only supported for form blocks")
99
+ n = self._layout_context.input_count
100
+ parsers = self._layout_context.result_parsers
101
+ out: list[Any] = []
102
+ for i in range(n):
103
+ ev = await_input()
104
+ if i < len(parsers):
105
+ out.append(parsers[i](ev.data))
106
+ else:
107
+ out.append(ev.data)
108
+ return tuple(out)
109
+
110
+
111
+ __all__ = ["LayoutContext", "LayoutHandle", "_current_layout"]
@@ -0,0 +1,37 @@
1
+ """Buttons block implementation."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from yera.events.blocks.base import _BlockFactory
6
+ from yera.events.models import ButtonsData
7
+ from yera.events.stream import push_output
8
+
9
+
10
+ class _ButtonsBlockFactory(_BlockFactory):
11
+ """Factory for creating button blocks."""
12
+
13
+ def __init__(self):
14
+ super().__init__("buttons")
15
+
16
+ def __call__(
17
+ self,
18
+ options: list[str],
19
+ label: str | None = None,
20
+ ):
21
+ event = self._create_block_output_event(
22
+ data=ButtonsData(options=options, label=label),
23
+ message_type="await_user",
24
+ )
25
+ push_output(event)
26
+
27
+
28
+ # Create a single shared factory instance
29
+ _buttons_factory = _ButtonsBlockFactory()
30
+
31
+
32
+ def request_input_buttons(options: list[str], label: str | None = None):
33
+ """Request buttons input from the user."""
34
+ return _buttons_factory(options, label)
35
+
36
+
37
+ __all__ = ["request_input_buttons"]
@@ -0,0 +1,26 @@
1
+ """Columns block implementation."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from yera.events.blocks.base import LayoutHandle, _BlockFactory
6
+ from yera.events.models import ColumnsData
7
+
8
+
9
+ class _ColumnsBlockFactory(_BlockFactory):
10
+ """Factory for columns blocks."""
11
+
12
+ def __init__(self):
13
+ super().__init__("columns")
14
+
15
+ def __call__(self, n: int, border: bool = False) -> LayoutHandle:
16
+ """Return a context manager for creating column layouts with n columns."""
17
+ block_id = self._generate_block_id()
18
+ return LayoutHandle(
19
+ block_id, "columns", ColumnsData(showBorder=border, column_count=n)
20
+ )
21
+
22
+
23
+ # Create the columns callable/context manager
24
+ columns = _ColumnsBlockFactory()
25
+
26
+ __all__ = ["columns"]
@@ -0,0 +1,24 @@
1
+ """Container block implementation."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from yera.events.blocks.base import LayoutHandle, _BlockFactory
6
+ from yera.events.models import ContainerData
7
+
8
+
9
+ class _ContainerBlockFactory(_BlockFactory):
10
+ """Factory for container blocks."""
11
+
12
+ def __init__(self):
13
+ super().__init__("container")
14
+
15
+ def __call__(self, border: bool = False) -> LayoutHandle:
16
+ """Return a context manager for creating container layouts."""
17
+ block_id = self._generate_block_id()
18
+ return LayoutHandle(block_id, "container", ContainerData(showBorder=border))
19
+
20
+
21
+ # Create the container callable/context manager
22
+ container = _ContainerBlockFactory()
23
+
24
+ __all__ = ["container"]
@@ -0,0 +1,50 @@
1
+ """Date picker block implementation."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from datetime import date
6
+
7
+ from yera.events.blocks.base import _BlockFactory
8
+ from yera.events.models import DatePickerData
9
+ from yera.events.stream import push_output
10
+
11
+
12
+ class _DatePickerBlockFactory(_BlockFactory):
13
+ """Factory for creating date picker blocks."""
14
+
15
+ def __init__(self):
16
+ super().__init__("date")
17
+
18
+ def __call__(
19
+ self,
20
+ label: str,
21
+ default_date: date | str | None = None,
22
+ ):
23
+ """Create a date picker block."""
24
+ # Default to today's date if not provided
25
+ if default_date is None:
26
+ default_date = date.today()
27
+ elif isinstance(default_date, str):
28
+ # Parse string to date if provided as string
29
+ default_date = date.fromisoformat(default_date)
30
+
31
+ data = DatePickerData(value=default_date, label=label)
32
+
33
+ # Use shared method with await_user message_type
34
+ event = self._create_block_output_event(data, message_type="await_user")
35
+ push_output(event)
36
+
37
+
38
+ # Create a single shared factory instance
39
+ _date_picker_factory = _DatePickerBlockFactory()
40
+
41
+
42
+ def request_input_date_picker(
43
+ label: str,
44
+ default_date: date | str | None = None,
45
+ ):
46
+ """Request date picker input from the user."""
47
+ return _date_picker_factory(label, default_date)
48
+
49
+
50
+ __all__ = ["request_input_date_picker"]
@@ -0,0 +1,39 @@
1
+ from __future__ import annotations
2
+
3
+ from pydantic import BaseModel
4
+
5
+ from yera.events.blocks.base import _BlockFactory
6
+ from yera.events.models import ExitEventData
7
+ from yera.events.stream import push_output
8
+
9
+
10
+ class _ExitBlockFactory(_BlockFactory):
11
+ def __init__(self):
12
+ super().__init__("exit")
13
+
14
+ def __call__(self, exit_code: int, reason: str | None, return_value: str | None):
15
+ return_type = type(return_value).__name__
16
+
17
+ if isinstance(return_value, BaseModel):
18
+ return_value = return_value.model_dump_json()
19
+
20
+ event = self._create_block_output_event(
21
+ data=ExitEventData(
22
+ exit_code=exit_code,
23
+ reason=reason,
24
+ return_type=return_type,
25
+ return_value=str(return_value),
26
+ ),
27
+ message_type="informational",
28
+ )
29
+ push_output(event)
30
+
31
+
32
+ exit_event = _ExitBlockFactory()
33
+
34
+
35
+ def quit_event():
36
+ exit_event(exit_code=0, reason="User quit", return_value=None)
37
+
38
+
39
+ __all__ = ["exit_event", "quit_event"]
@@ -0,0 +1,24 @@
1
+ """Form block implementation."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from yera.events.blocks.base import LayoutHandle, _BlockFactory
6
+ from yera.events.models import ContainerData
7
+
8
+
9
+ class _FormBlockFactory(_BlockFactory):
10
+ """Factory for form blocks (layout with await_user children and submit)."""
11
+
12
+ def __init__(self):
13
+ super().__init__("form")
14
+
15
+ def __call__(self, border: bool = False) -> LayoutHandle:
16
+ """Return a context manager for creating form layouts."""
17
+ block_id = self._generate_block_id()
18
+ return LayoutHandle(block_id, "form", ContainerData(showBorder=border))
19
+
20
+
21
+ # Create the form callable/context manager
22
+ form = _FormBlockFactory()
23
+
24
+ __all__ = ["form"]
@@ -0,0 +1,22 @@
1
+ from __future__ import annotations
2
+
3
+ from yera.events.blocks.base import _BlockFactory
4
+ from yera.events.models import MarkdownData
5
+ from yera.events.stream import push_output
6
+
7
+
8
+ class _InputEchoBlockFactory(_BlockFactory):
9
+ def __init__(self):
10
+ super().__init__("input_echo")
11
+
12
+ def __call__(self, content):
13
+ event = self._create_block_output_event(
14
+ data=MarkdownData(content=content),
15
+ message_type="informational",
16
+ )
17
+ push_output(event)
18
+
19
+
20
+ input_echo = _InputEchoBlockFactory()
21
+
22
+ __all__ = ["input_echo"]
@@ -0,0 +1,31 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Literal
4
+
5
+ from yera.events.blocks.base import _BlockFactory
6
+ from yera.events.models import InputRequestData
7
+ from yera.events.stream import push_output
8
+
9
+
10
+ class _InputRequestBlockFactory(_BlockFactory):
11
+ def __init__(self):
12
+ super().__init__("input_request")
13
+
14
+ def __call__(self, message: str | None, input_type: Literal["text"]):
15
+ event = self._create_block_output_event(
16
+ data=InputRequestData(message=message, type=input_type),
17
+ message_type="await_user",
18
+ )
19
+ push_output(event)
20
+
21
+
22
+ # Create a single shared factory instance
23
+ _input_request_factory = _InputRequestBlockFactory()
24
+
25
+
26
+ def request_input_text(message: str | None = None):
27
+ """Request text input from the user."""
28
+ return _input_request_factory(message or "", "text")
29
+
30
+
31
+ __all__ = ["request_input_text"]
@@ -0,0 +1,97 @@
1
+ """Line chart block implementation."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from collections.abc import Sequence
6
+ from typing import TYPE_CHECKING
7
+
8
+ if TYPE_CHECKING:
9
+ import pandas as pd
10
+
11
+ from yera.events.blocks.base import _ChartBlockFactory
12
+ from yera.events.blocks.base.chart import _ChartConversionData
13
+ from yera.events.models import LineChartData
14
+ from yera.events.stream import push_output
15
+
16
+
17
+ class _LineChartBlockFactory(_ChartBlockFactory):
18
+ """Factory for creating line chart blocks, matching Streamlit's st.line_chart API."""
19
+
20
+ def __init__(self):
21
+ super().__init__("line_chart")
22
+
23
+ def _create_chart_data_from_conversion(
24
+ self,
25
+ conversion_data: _ChartConversionData,
26
+ chart_specific_params: dict,
27
+ ) -> LineChartData:
28
+ """Convert intermediate data to LineChartData."""
29
+ if len(chart_specific_params) > 0:
30
+ raise ValueError("Line charts don't have specific parameters")
31
+
32
+ # LineChartData omits x_ticks and x_label when x parameter was not provided
33
+ x_ticks = (
34
+ conversion_data.x_categories
35
+ if conversion_data.x_label is not None
36
+ else None
37
+ )
38
+ x_label = conversion_data.x_label
39
+
40
+ return LineChartData(
41
+ x_label=x_label,
42
+ x_ticks=x_ticks,
43
+ y_label=conversion_data.y_label,
44
+ y_values=conversion_data.y_values,
45
+ colour_label=conversion_data.colour_label,
46
+ colour_series=conversion_data.colour_categories,
47
+ colour_values=conversion_data.colour_values,
48
+ )
49
+
50
+ def __call__(
51
+ self,
52
+ data: pd.DataFrame,
53
+ *,
54
+ x: str | None = None,
55
+ y: str | Sequence[str] | None = None,
56
+ colour: str | Sequence[str] | None = None,
57
+ ) -> None:
58
+ """Create a line chart block, matching Streamlit's st.line_chart() signature.
59
+
60
+ Args:
61
+ data: DataFrame to plot
62
+ x: Column name for x-axis (None = use index, or omit x_ticks if y is specified)
63
+ y: Column name(s) for y-axis (None = use all columns)
64
+ colour: Column name for colour grouping, or list of colors
65
+
66
+ Returns:
67
+ None (informational block)
68
+
69
+ """
70
+ if x is None and y is None:
71
+ conversion_data = self._convert_default_format(data)
72
+ elif x is not None and isinstance(y, str):
73
+ conversion_data = self._convert_long_format(data, x, y, colour)
74
+ elif isinstance(y, Sequence) and not isinstance(y, str):
75
+ # Wide format: y is a sequence, x may be None or a string
76
+ conversion_data = self._convert_wide_format(data, x, y, colour)
77
+ else:
78
+ raise ValueError(
79
+ f"Unsupported line_chart parameter combination: x={x}, y={y}"
80
+ )
81
+
82
+ chart_data = self._create_chart_data_from_conversion(
83
+ conversion_data,
84
+ {}, # Line charts don't have chart-specific params
85
+ )
86
+
87
+ event = self._create_block_output_event(
88
+ chart_data, message_type="informational"
89
+ )
90
+ push_output(event)
91
+ return
92
+
93
+
94
+ # Create the line_chart callable
95
+ line_chart = _LineChartBlockFactory()
96
+
97
+ __all__ = ["line_chart"]
@@ -0,0 +1,67 @@
1
+ """Markdown block implementation."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from yera.events.blocks.base import _BlockFactory, _StreamHandle
6
+ from yera.events.models import MarkdownData
7
+ from yera.events.stream import push_output
8
+
9
+
10
+ class MarkdownStream(_StreamHandle):
11
+ """Stream handle for creating multiple chunks of the same markdown block."""
12
+
13
+ def __init__(self, block_id: str):
14
+ super().__init__(block_id, "markdown")
15
+
16
+ def __enter__(self):
17
+ return self
18
+
19
+ def __exit__(self, exc_type, exc_value, traceback):
20
+ return False
21
+
22
+ def append(self, content: str) -> None:
23
+ """Append a new chunk to this markdown block."""
24
+ event = self._create_chunk_event(
25
+ data=MarkdownData(content=content),
26
+ )
27
+ push_output(event)
28
+
29
+ def new_line(self, content: str) -> None:
30
+ """Append a new line to this markdown block."""
31
+ new_line_content = "\n\n" + content
32
+ self.append(new_line_content)
33
+
34
+
35
+ class _MarkdownBlockFactory(_BlockFactory):
36
+ """Factory for markdown blocks."""
37
+
38
+ def __init__(self):
39
+ super().__init__("markdown")
40
+
41
+ def __call__(self, content: str | None = None) -> MarkdownStream:
42
+ """Create a markdown block or return a stream for context manager usage.
43
+
44
+ Args:
45
+ content: If provided, immediately emits a single markdown chunk.
46
+
47
+ Returns:
48
+ A MarkdownStream that can be used as a context manager for streaming
49
+ additional chunks.
50
+
51
+ """
52
+ block_id = self._generate_block_id()
53
+
54
+ stream = MarkdownStream(block_id)
55
+
56
+ if content is not None:
57
+ # Direct call or initial content for a stream: emit first chunk immediately
58
+ stream.append(content)
59
+
60
+ # Always return the stream, even if used only for a single chunk
61
+ return stream
62
+
63
+
64
+ # Create the markdown callable/context manager
65
+ markdown = _MarkdownBlockFactory()
66
+
67
+ __all__ = ["markdown"]
@@ -0,0 +1,54 @@
1
+ """Slider block implementation."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from yera.events.blocks.base import _BlockFactory
6
+ from yera.events.models import SliderData
7
+ from yera.events.stream import push_output
8
+
9
+
10
+ class _SliderBlockFactory(_BlockFactory):
11
+ """Factory for creating slider blocks."""
12
+
13
+ def __init__(self):
14
+ super().__init__("slider")
15
+
16
+ def __call__(
17
+ self,
18
+ min_value: float,
19
+ max_value: float,
20
+ label: str,
21
+ default_value: float | None = None,
22
+ ):
23
+ """Create a slider block."""
24
+ # Default to midpoint if not provided
25
+ if default_value is None:
26
+ default_value = (min_value + max_value) / 2
27
+
28
+ data = SliderData(
29
+ min_value=min_value,
30
+ max_value=max_value,
31
+ initial_value=default_value,
32
+ label=label,
33
+ )
34
+
35
+ # Use shared method with await_user message_type
36
+ event = self._create_block_output_event(data, message_type="await_user")
37
+ push_output(event)
38
+
39
+
40
+ # Create a single shared factory instance
41
+ _slider_factory = _SliderBlockFactory()
42
+
43
+
44
+ def request_input_slider(
45
+ min_value: float,
46
+ max_value: float,
47
+ label: str,
48
+ default_value: float | None = None,
49
+ ):
50
+ """Request slider input from the user."""
51
+ return _slider_factory(min_value, max_value, label, default_value)
52
+
53
+
54
+ __all__ = ["request_input_slider"]
@@ -0,0 +1,55 @@
1
+ """Spinner block implementation."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from yera.events.blocks.base import _BlockFactory, _StreamHandle
6
+ from yera.events.models import SpinnerData
7
+ from yera.events.stream import push_output
8
+
9
+
10
+ class SpinnerStream(_StreamHandle):
11
+ """Stream handle for creating multiple chunks of the same spinner block."""
12
+
13
+ def __init__(self, block_id: str, initial_message: str):
14
+ super().__init__(block_id, "spinner")
15
+ self.initial_message = initial_message
16
+
17
+ def __enter__(self):
18
+ event = self._create_chunk_event(
19
+ data=SpinnerData(status="active", message=self.initial_message),
20
+ )
21
+ push_output(event)
22
+ return self
23
+
24
+ def __exit__(self, exc_type, exc_value, traceback):
25
+ event = self._create_chunk_event(
26
+ data=SpinnerData(status="complete"),
27
+ )
28
+ push_output(event)
29
+ return False
30
+
31
+ def update(self, message: str) -> None:
32
+ """Create an update chunk with status 'active'."""
33
+ event = self._create_chunk_event(
34
+ data=SpinnerData(status="active", message=message),
35
+ )
36
+ push_output(event)
37
+
38
+
39
+ class _SpinnerBlockFactory(_BlockFactory):
40
+ """Factory for spinner blocks. Returns a context manager when called with message."""
41
+
42
+ def __init__(self):
43
+ super().__init__("spinner")
44
+
45
+ def __call__(self, message: str) -> SpinnerStream:
46
+ """Return a context manager for creating multiple spinner chunks."""
47
+ block_id = self._generate_block_id()
48
+ return SpinnerStream(block_id, message)
49
+
50
+
51
+ # Create the spinner callable/context manager
52
+ spinner = _SpinnerBlockFactory()
53
+
54
+
55
+ __all__ = ["spinner"]
@@ -0,0 +1,22 @@
1
+ from __future__ import annotations
2
+
3
+ from yera.events.blocks.base import _BlockFactory
4
+ from yera.events.models import MarkdownData
5
+ from yera.events.stream import push_output
6
+
7
+
8
+ class _SystemPromptBlockFactory(_BlockFactory):
9
+ def __init__(self):
10
+ super().__init__("system_prompt")
11
+
12
+ def __call__(self, content):
13
+ event = self._create_block_output_event(
14
+ data=MarkdownData(content=content),
15
+ message_type="informational",
16
+ )
17
+ push_output(event)
18
+
19
+
20
+ system_prompt = _SystemPromptBlockFactory()
21
+
22
+ __all__ = ["system_prompt"]