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.
- infra_mvp/base_client.py +29 -0
- infra_mvp/base_server.py +68 -0
- infra_mvp/monitoring/__init__.py +15 -0
- infra_mvp/monitoring/metrics.py +185 -0
- infra_mvp/stream/README.md +56 -0
- infra_mvp/stream/__init__.py +14 -0
- infra_mvp/stream/__main__.py +101 -0
- infra_mvp/stream/agents/demos/financial/chart_additions_plan.md +170 -0
- infra_mvp/stream/agents/demos/financial/portfolio_assistant_stream.json +1571 -0
- infra_mvp/stream/agents/reference/blocks/action.json +170 -0
- infra_mvp/stream/agents/reference/blocks/button.json +66 -0
- infra_mvp/stream/agents/reference/blocks/date.json +65 -0
- infra_mvp/stream/agents/reference/blocks/input_prompt.json +94 -0
- infra_mvp/stream/agents/reference/blocks/layout.json +288 -0
- infra_mvp/stream/agents/reference/blocks/markdown.json +344 -0
- infra_mvp/stream/agents/reference/blocks/slider.json +67 -0
- infra_mvp/stream/agents/reference/blocks/spinner.json +110 -0
- infra_mvp/stream/agents/reference/blocks/table.json +56 -0
- infra_mvp/stream/agents/reference/chat_dynamics/branching_test_stream.json +145 -0
- infra_mvp/stream/app.py +49 -0
- infra_mvp/stream/container.py +112 -0
- infra_mvp/stream/schemas/__init__.py +16 -0
- infra_mvp/stream/schemas/agent.py +24 -0
- infra_mvp/stream/schemas/interaction.py +28 -0
- infra_mvp/stream/schemas/session.py +30 -0
- infra_mvp/stream/server.py +321 -0
- infra_mvp/stream/services/__init__.py +12 -0
- infra_mvp/stream/services/agent_service.py +40 -0
- infra_mvp/stream/services/event_converter.py +83 -0
- infra_mvp/stream/services/session_service.py +247 -0
- yera/__init__.py +50 -1
- yera/agents/__init__.py +2 -0
- yera/agents/context.py +41 -0
- yera/agents/dataclasses.py +69 -0
- yera/agents/decorator.py +207 -0
- yera/agents/discovery.py +124 -0
- yera/agents/typing/__init__.py +0 -0
- yera/agents/typing/coerce.py +408 -0
- yera/agents/typing/utils.py +19 -0
- yera/agents/typing/validate.py +206 -0
- yera/cli.py +377 -0
- yera/config/__init__.py +1 -0
- yera/config/config_utils.py +164 -0
- yera/config/function_config.py +55 -0
- yera/config/logging.py +18 -0
- yera/config/tool_config.py +8 -0
- yera/config2/__init__.py +8 -0
- yera/config2/dataclasses.py +534 -0
- yera/config2/keyring.py +270 -0
- yera/config2/paths.py +28 -0
- yera/config2/read.py +113 -0
- yera/config2/setup.py +109 -0
- yera/config2/setup_handlers/__init__.py +1 -0
- yera/config2/setup_handlers/anthropic.py +126 -0
- yera/config2/setup_handlers/azure.py +236 -0
- yera/config2/setup_handlers/base.py +125 -0
- yera/config2/setup_handlers/llama_cpp.py +205 -0
- yera/config2/setup_handlers/ollama.py +157 -0
- yera/config2/setup_handlers/openai.py +137 -0
- yera/config2/write.py +87 -0
- yera/dsl/__init__.py +0 -0
- yera/dsl/functions.py +94 -0
- yera/dsl/struct.py +20 -0
- yera/dsl/workspace.py +79 -0
- yera/events/__init__.py +57 -0
- yera/events/blocks/__init__.py +68 -0
- yera/events/blocks/action.py +57 -0
- yera/events/blocks/bar_chart.py +92 -0
- yera/events/blocks/base/__init__.py +20 -0
- yera/events/blocks/base/base.py +166 -0
- yera/events/blocks/base/chart.py +288 -0
- yera/events/blocks/base/layout.py +111 -0
- yera/events/blocks/buttons.py +37 -0
- yera/events/blocks/columns.py +26 -0
- yera/events/blocks/container.py +24 -0
- yera/events/blocks/date_picker.py +50 -0
- yera/events/blocks/exit.py +39 -0
- yera/events/blocks/form.py +24 -0
- yera/events/blocks/input_echo.py +22 -0
- yera/events/blocks/input_request.py +31 -0
- yera/events/blocks/line_chart.py +97 -0
- yera/events/blocks/markdown.py +67 -0
- yera/events/blocks/slider.py +54 -0
- yera/events/blocks/spinner.py +55 -0
- yera/events/blocks/system_prompt.py +22 -0
- yera/events/blocks/table.py +291 -0
- yera/events/models/__init__.py +39 -0
- yera/events/models/block_data.py +112 -0
- yera/events/models/in_event.py +7 -0
- yera/events/models/out_event.py +75 -0
- yera/events/runtime.py +187 -0
- yera/events/stream.py +91 -0
- yera/models/__init__.py +0 -0
- yera/models/data_classes.py +20 -0
- yera/models/llm_atlas_proxy.py +44 -0
- yera/models/llm_context.py +99 -0
- yera/models/llm_interfaces/__init__.py +0 -0
- yera/models/llm_interfaces/anthropic.py +153 -0
- yera/models/llm_interfaces/aws_bedrock.py +14 -0
- yera/models/llm_interfaces/azure_openai.py +143 -0
- yera/models/llm_interfaces/base.py +26 -0
- yera/models/llm_interfaces/interface_registry.py +74 -0
- yera/models/llm_interfaces/llama_cpp.py +136 -0
- yera/models/llm_interfaces/mock.py +29 -0
- yera/models/llm_interfaces/ollama_interface.py +118 -0
- yera/models/llm_interfaces/open_ai.py +150 -0
- yera/models/llm_workspace.py +19 -0
- yera/models/model_atlas.py +139 -0
- yera/models/model_definition.py +38 -0
- yera/models/model_factory.py +33 -0
- yera/opaque/__init__.py +9 -0
- yera/opaque/base.py +20 -0
- yera/opaque/decorator.py +8 -0
- yera/opaque/markdown.py +57 -0
- yera/opaque/opaque_function.py +25 -0
- yera/tools/__init__.py +29 -0
- yera/tools/atlas_tool.py +20 -0
- yera/tools/base.py +24 -0
- yera/tools/decorated_tool.py +18 -0
- yera/tools/decorator.py +35 -0
- yera/tools/tool_atlas.py +51 -0
- yera/tools/tool_utils.py +361 -0
- yera/ui/dist/404.html +1 -0
- yera/ui/dist/__next.__PAGE__.txt +10 -0
- yera/ui/dist/__next._full.txt +23 -0
- yera/ui/dist/__next._head.txt +6 -0
- yera/ui/dist/__next._index.txt +5 -0
- yera/ui/dist/__next._tree.txt +7 -0
- yera/ui/dist/_next/static/chunks/4c4688e1ff21ad98.js +1 -0
- yera/ui/dist/_next/static/chunks/652cd53c27924d50.js +4 -0
- yera/ui/dist/_next/static/chunks/786d2107b51e8499.css +1 -0
- yera/ui/dist/_next/static/chunks/7de9141b1af425c3.js +1 -0
- yera/ui/dist/_next/static/chunks/87ef65064d3524c1.js +2 -0
- yera/ui/dist/_next/static/chunks/a6dad97d9634a72d.js +1 -0
- yera/ui/dist/_next/static/chunks/a6dad97d9634a72d.js.map +1 -0
- yera/ui/dist/_next/static/chunks/c4c79d5d0b280aeb.js +1 -0
- yera/ui/dist/_next/static/chunks/dc2d2a247505d66f.css +5 -0
- yera/ui/dist/_next/static/chunks/f773f714b55ec620.js +37 -0
- yera/ui/dist/_next/static/chunks/turbopack-98b3031e1b1dbc33.js +4 -0
- yera/ui/dist/_next/static/lnhYLzJ1-a5EfNbW1uFF6/_buildManifest.js +11 -0
- yera/ui/dist/_next/static/lnhYLzJ1-a5EfNbW1uFF6/_clientMiddlewareManifest.json +1 -0
- yera/ui/dist/_next/static/lnhYLzJ1-a5EfNbW1uFF6/_ssgManifest.js +1 -0
- yera/ui/dist/_next/static/media/14e23f9b59180572-s.9c448f3c.woff2 +0 -0
- yera/ui/dist/_next/static/media/2a65768255d6b625-s.p.d19752fb.woff2 +0 -0
- yera/ui/dist/_next/static/media/2b2eb4836d2dad95-s.f36de3af.woff2 +0 -0
- yera/ui/dist/_next/static/media/31183d9fd602dc89-s.c4ff9b73.woff2 +0 -0
- yera/ui/dist/_next/static/media/3fcb63a1ac6a562e-s.2f77a576.woff2 +0 -0
- yera/ui/dist/_next/static/media/45ec8de98929b0f6-s.81056204.woff2 +0 -0
- yera/ui/dist/_next/static/media/4fa387ec64143e14-s.c1fdd6c2.woff2 +0 -0
- yera/ui/dist/_next/static/media/65c558afe41e89d6-s.e2c8389a.woff2 +0 -0
- yera/ui/dist/_next/static/media/67add6cc0f54b8cf-s.8ce53448.woff2 +0 -0
- yera/ui/dist/_next/static/media/7178b3e590c64307-s.b97b3418.woff2 +0 -0
- yera/ui/dist/_next/static/media/797e433ab948586e-s.p.dbea232f.woff2 +0 -0
- yera/ui/dist/_next/static/media/8a480f0b521d4e75-s.8e0177b5.woff2 +0 -0
- yera/ui/dist/_next/static/media/a8ff2d5d0ccb0d12-s.fc5b72a7.woff2 +0 -0
- yera/ui/dist/_next/static/media/aae5f0be330e13db-s.p.853e26d6.woff2 +0 -0
- yera/ui/dist/_next/static/media/b11a6ccf4a3edec7-s.2113d282.woff2 +0 -0
- yera/ui/dist/_next/static/media/b49b0d9b851e4899-s.4f3fa681.woff2 +0 -0
- yera/ui/dist/_next/static/media/bbc41e54d2fcbd21-s.799d8ef8.woff2 +0 -0
- yera/ui/dist/_next/static/media/caa3a2e1cccd8315-s.p.853070df.woff2 +0 -0
- yera/ui/dist/_next/static/media/favicon.0b3bf435.ico +0 -0
- yera/ui/dist/_not-found/__next._full.txt +14 -0
- yera/ui/dist/_not-found/__next._head.txt +6 -0
- yera/ui/dist/_not-found/__next._index.txt +5 -0
- yera/ui/dist/_not-found/__next._not-found.__PAGE__.txt +5 -0
- yera/ui/dist/_not-found/__next._not-found.txt +4 -0
- yera/ui/dist/_not-found/__next._tree.txt +2 -0
- yera/ui/dist/_not-found.html +1 -0
- yera/ui/dist/_not-found.txt +14 -0
- yera/ui/dist/agent-icon.svg +3 -0
- yera/ui/dist/favicon.ico +0 -0
- yera/ui/dist/file.svg +1 -0
- yera/ui/dist/globe.svg +1 -0
- yera/ui/dist/index.html +1 -0
- yera/ui/dist/index.txt +23 -0
- yera/ui/dist/logo/full_logo.png +0 -0
- yera/ui/dist/logo/rune_logo.png +0 -0
- yera/ui/dist/logo/rune_logo_borderless.png +0 -0
- yera/ui/dist/logo/text_logo.png +0 -0
- yera/ui/dist/next.svg +1 -0
- yera/ui/dist/send.png +0 -0
- yera/ui/dist/send_single.png +0 -0
- yera/ui/dist/vercel.svg +1 -0
- yera/ui/dist/window.svg +1 -0
- yera/utils/__init__.py +1 -0
- yera/utils/path_utils.py +38 -0
- yera-0.2.0.dist-info/METADATA +65 -0
- yera-0.2.0.dist-info/RECORD +190 -0
- {yera-0.1.0.dist-info → yera-0.2.0.dist-info}/WHEEL +1 -1
- yera-0.2.0.dist-info/entry_points.txt +2 -0
- yera-0.1.0.dist-info/METADATA +0 -11
- 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"]
|