zrb 1.5.1__py3-none-any.whl → 1.5.3__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.
- zrb/__main__.py +1 -1
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/README.md +127 -5
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/requirements.txt +7 -7
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/test/test_homepage.py +8 -7
- zrb/llm_config.py +22 -15
- zrb/task/llm_task.py +136 -20
- {zrb-1.5.1.dist-info → zrb-1.5.3.dist-info}/METADATA +13 -14
- {zrb-1.5.1.dist-info → zrb-1.5.3.dist-info}/RECORD +10 -10
- {zrb-1.5.1.dist-info → zrb-1.5.3.dist-info}/WHEEL +0 -0
- {zrb-1.5.1.dist-info → zrb-1.5.3.dist-info}/entry_points.txt +0 -0
zrb/__main__.py
CHANGED
@@ -16,7 +16,7 @@ def serve_cli():
|
|
16
16
|
zrb_init_path_list = _get_zrb_init_path_list()
|
17
17
|
# load init scripts
|
18
18
|
for init_script in INIT_SCRIPTS:
|
19
|
-
abs_init_script = os.path.abspath(init_script)
|
19
|
+
abs_init_script = os.path.abspath(os.path.expanduser(init_script))
|
20
20
|
if abs_init_script not in zrb_init_path_list:
|
21
21
|
load_file(abs_init_script, -1)
|
22
22
|
# load zrb init
|
@@ -1,7 +1,129 @@
|
|
1
|
-
# App Name
|
1
|
+
# My App Name
|
2
2
|
|
3
|
-
|
3
|
+
Welcome to My App Name! This application is designed to help you start your project with a flexible architecture that can scale as your needs grow. My App Name supports both monolithic and microservices architectures, allowing you to start small and expand without rewriting your codebase.
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
-
|
5
|
+
## Key Features
|
6
|
+
|
7
|
+
- **Modular-Monolith Architecture**: My App Name is built with a modular-monolith architecture, providing a clean interface for inter-module communication. This allows you to run My App Name as a monolith or as microservices without altering your code.
|
8
|
+
|
9
|
+
- **Low Coupling, High Cohesion**: The architecture ensures low coupling and high cohesion, making it easy to split your code into microservices when needed.
|
10
|
+
|
11
|
+
## How It Works
|
12
|
+
|
13
|
+
### Inter-Module Communication
|
14
|
+
|
15
|
+
Each module in My App Name is independent and communicates with others through a `Client` object. The `Client` is an interface with two implementations: `ApiClient` and `DirectClient`.
|
16
|
+
|
17
|
+
- **ApiClient**: Used when running My App Name as microservices. It communicates over HTTP using a base URL.
|
18
|
+
- **DirectClient**: Used when running My App Name as a monolith. It allows direct method calls between modules.
|
19
|
+
|
20
|
+
### Code Examples
|
21
|
+
|
22
|
+
Here's how you can use the `as_api_client` and `as_direct_client` methods:
|
23
|
+
|
24
|
+
```python
|
25
|
+
# Using as_api_client
|
26
|
+
from my_app_name.config import APP_AUTH_BASE_URL
|
27
|
+
from my_app_name.module.auth.service.permission.permission_service_factory import permission_service
|
28
|
+
|
29
|
+
# Create an API client for the permission service
|
30
|
+
permission_api_client = permission_service.as_api_client(base_url=APP_AUTH_BASE_URL)
|
31
|
+
|
32
|
+
# Using as_direct_client
|
33
|
+
from my_app_name.module.auth.service.role.role_service_factory import role_service
|
34
|
+
|
35
|
+
# Create a direct client for the role service
|
36
|
+
role_direct_client = role_service.as_direct_client()
|
37
|
+
```
|
38
|
+
## Application Architecture
|
39
|
+
|
40
|
+
My App Name follows a modular-monolith architecture. Each module (e.g., Auth, Library) encapsulates a specific business capability. The Gateway module acts as the entry point for user interactions (e.g., web UI).
|
41
|
+
|
42
|
+
**Communication Modes:**
|
43
|
+
|
44
|
+
1. **Monolith (Direct Communication):**
|
45
|
+
```
|
46
|
+
+---------+ +---------+
|
47
|
+
| Gateway | ----> | Auth | (e.g., for login, permission checks)
|
48
|
+
| (UI) | | Service |
|
49
|
+
+---------+ +---------+
|
50
|
+
| ^
|
51
|
+
| | (Library might call Auth for specific checks)
|
52
|
+
| |
|
53
|
+
v |
|
54
|
+
+---------+ -----------+
|
55
|
+
| Library |
|
56
|
+
| Service |
|
57
|
+
+---------+
|
58
|
+
(Gateway also calls Library directly)
|
59
|
+
(DirectClient calls between services if needed)
|
60
|
+
```
|
61
|
+
Modules communicate directly via `DirectClient` implementations. The Gateway calls necessary services, and services can call each other directly if required.
|
62
|
+
|
63
|
+
2. **Microservices (API Communication):**
|
64
|
+
```
|
65
|
+
+---------+ +---------+
|
66
|
+
| Gateway | ----> | Auth | (e.g., via Auth API)
|
67
|
+
| (UI) | | Service |
|
68
|
+
| | | (API) |
|
69
|
+
+---------+ +---------+
|
70
|
+
| ^
|
71
|
+
| | (Library Service might call Auth API)
|
72
|
+
| |
|
73
|
+
v |
|
74
|
+
+---------+ -----------+
|
75
|
+
| Library |
|
76
|
+
| Service |
|
77
|
+
| (API) |
|
78
|
+
+---------+
|
79
|
+
(Gateway also calls Library API)
|
80
|
+
(ApiClient calls via HTTP between services if needed)
|
81
|
+
```
|
82
|
+
Modules communicate via `ApiClient` implementations over HTTP/API calls. The Gateway calls necessary service APIs, and services can call each other's APIs if required.
|
83
|
+
|
84
|
+
## Factory Pattern
|
85
|
+
|
86
|
+
The application utilizes the Factory pattern extensively, particularly for creating client, service, and repository instances. This allows the application to switch between different implementations based on configuration settings.
|
87
|
+
|
88
|
+
**Example (`my_app_name/module/auth/client/auth_client_factory.py`):**
|
89
|
+
|
90
|
+
```python
|
91
|
+
from my_app_name.config import APP_COMMUNICATION
|
92
|
+
from my_app_name.module.auth.client.auth_api_client import AuthAPIClient
|
93
|
+
from my_app_name.module.auth.client.auth_client import AuthClient
|
94
|
+
from my_app_name.module.auth.client.auth_direct_client import AuthDirectClient
|
95
|
+
|
96
|
+
# Selects the client based on the configuration
|
97
|
+
if APP_COMMUNICATION == "direct":
|
98
|
+
auth_client: AuthClient = AuthDirectClient() # Used in Monolith mode
|
99
|
+
elif APP_COMMUNICATION == "api":
|
100
|
+
auth_client: AuthClient = AuthAPIClient() # Used in Microservices mode
|
101
|
+
```
|
102
|
+
|
103
|
+
By changing the `APP_COMMUNICATION` variable in `my_app_name/config.py`, you can switch how modules communicate without changing the core module logic. Similar factories exist for services and repositories (e.g., switching between database and in-memory implementations based on `APP_REPOSITORY_TYPE`).
|
104
|
+
|
105
|
+
## Key Folders and Files
|
106
|
+
|
107
|
+
- `my_app_name/config.py`: Central configuration file (database connections, communication mode, etc.).
|
108
|
+
- `my_app_name/main.py`: Main application entry point.
|
109
|
+
- `my_app_name/common/`: Shared utilities, base classes (e.g., `app_factory.py`, `base_service.py`).
|
110
|
+
- `my_app_name/module/`: Contains the application modules (e.g., `auth`, `library`, `gateway`).
|
111
|
+
- `my_app_name/module/<module_name>/`: Each module directory typically contains:
|
112
|
+
- `client/`: Client interfaces (`*_client.py`, `*_api_client.py`, `*_direct_client.py`) and factories (`*_client_factory.py`).
|
113
|
+
- `service/`: Business logic implementation (`*_service.py`) and factories (`*_service_factory.py`).
|
114
|
+
- `repository/`: Data access logic (`*_repository.py`, `*_db_repository.py`) and factories (`*_repository_factory.py`).
|
115
|
+
- `route.py`: API or UI routes for the module.
|
116
|
+
- `schema/`: Data transfer objects or database models (if applicable).
|
117
|
+
- `migration/`: Database migration scripts (if using Alembic).
|
118
|
+
- `my_app_name/schema/`: Shared data schemas used across modules.
|
119
|
+
- `my_app_name/test/`: Unit and integration tests.
|
120
|
+
- `my_app_name/_zrb/`: Tooling scripts (likely for code generation or automation).
|
121
|
+
|
122
|
+
|
123
|
+
## Principles
|
124
|
+
|
125
|
+
- Developers should be able to override everything with a reasonable amount of code.
|
126
|
+
- Simple tasks should only require a small amount of code.
|
127
|
+
- A bit of magic is okay as long as it's transparent and documented.
|
128
|
+
|
129
|
+
For more details, refer to the client implementations in `module/auth/client/auth_api_client.py` and `module/auth/client/auth_direct_client.py`.
|
@@ -1,12 +1,12 @@
|
|
1
|
-
fastapi[standard]~=0.115.
|
2
|
-
alembic~=1.
|
3
|
-
sqlmodel~=0.0.
|
1
|
+
fastapi[standard]~=0.115.12
|
2
|
+
alembic~=1.15.2
|
3
|
+
sqlmodel~=0.0.24
|
4
4
|
ulid-py~=1.1.0
|
5
5
|
passlib~=1.7.4
|
6
|
-
Jinja2~=3.1.
|
6
|
+
Jinja2~=3.1.6
|
7
7
|
python-jose~=3.4.0
|
8
8
|
passlib~=1.7.4
|
9
9
|
|
10
|
-
pytest~=8.3.
|
11
|
-
pytest-asyncio~=0.
|
12
|
-
pytest-cov~=6.
|
10
|
+
pytest~=8.3.5
|
11
|
+
pytest-asyncio~=0.26.0
|
12
|
+
pytest-cov~=6.1.0
|
@@ -1,15 +1,16 @@
|
|
1
|
-
import os
|
2
|
-
|
3
1
|
from fastapi.testclient import TestClient
|
4
2
|
from my_app_name.main import app
|
3
|
+
from my_app_name.module.auth.service.user.user_service_factory import user_service
|
5
4
|
from my_app_name.module.gateway.util.view import render_content
|
6
5
|
|
7
6
|
|
8
|
-
def test_homepage():
|
7
|
+
async def test_homepage():
|
8
|
+
current_user = await user_service.get_current_user(access_token=None)
|
9
9
|
client = TestClient(app, base_url="http://localhost")
|
10
10
|
response = client.get("/")
|
11
11
|
assert response.status_code == 200
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
12
|
+
assert response.text == render_content(
|
13
|
+
"homepage.html",
|
14
|
+
page_name="gateway.home",
|
15
|
+
current_user=current_user,
|
16
|
+
).body.decode("utf-8")
|
zrb/llm_config.py
CHANGED
@@ -38,27 +38,27 @@ class LLMConfig:
|
|
38
38
|
default_persona: str | None = None,
|
39
39
|
default_system_prompt: str | None = None,
|
40
40
|
):
|
41
|
-
self.
|
41
|
+
self._default_model_name = (
|
42
42
|
default_model_name
|
43
43
|
if default_model_name is not None
|
44
44
|
else os.getenv("ZRB_LLM_MODEL", None)
|
45
45
|
)
|
46
|
-
self.
|
46
|
+
self._default_model_base_url = (
|
47
47
|
default_base_url
|
48
48
|
if default_base_url is not None
|
49
49
|
else os.getenv("ZRB_LLM_BASE_URL", None)
|
50
50
|
)
|
51
|
-
self.
|
51
|
+
self._default_model_api_key = (
|
52
52
|
default_api_key
|
53
53
|
if default_api_key is not None
|
54
54
|
else os.getenv("ZRB_LLM_API_KEY", None)
|
55
55
|
)
|
56
|
-
self.
|
56
|
+
self._default_system_prompt = (
|
57
57
|
default_system_prompt
|
58
58
|
if default_system_prompt is not None
|
59
59
|
else os.getenv("ZRB_LLM_SYSTEM_PROMPT", None)
|
60
60
|
)
|
61
|
-
self.
|
61
|
+
self._default_persona = (
|
62
62
|
default_persona
|
63
63
|
if default_persona is not None
|
64
64
|
else os.getenv("ZRB_LLM_PERSONA", None)
|
@@ -67,24 +67,28 @@ class LLMConfig:
|
|
67
67
|
self._default_model = None
|
68
68
|
|
69
69
|
def _get_model_name(self) -> str | None:
|
70
|
-
return
|
70
|
+
return (
|
71
|
+
self._default_model_name if self._default_model_name is not None else None
|
72
|
+
)
|
71
73
|
|
72
74
|
def get_default_model_provider(self) -> Provider | str:
|
73
75
|
if self._default_provider is not None:
|
74
76
|
return self._default_provider
|
75
|
-
if self.
|
77
|
+
if self._default_model_base_url is None and self._default_model_api_key is None:
|
76
78
|
return "openai"
|
77
79
|
return OpenAIProvider(
|
78
|
-
base_url=self.
|
80
|
+
base_url=self._default_model_base_url, api_key=self._default_model_api_key
|
79
81
|
)
|
80
82
|
|
81
83
|
def get_default_system_prompt(self) -> str:
|
82
84
|
system_prompt = (
|
83
85
|
DEFAULT_SYSTEM_PROMPT
|
84
|
-
if self.
|
85
|
-
else self.
|
86
|
+
if self._default_system_prompt is None
|
87
|
+
else self._default_system_prompt
|
88
|
+
)
|
89
|
+
persona = (
|
90
|
+
DEFAULT_PERSONA if self._default_persona is None else self._default_persona
|
86
91
|
)
|
87
|
-
persona = DEFAULT_PERSONA if self._persona is None else self._persona
|
88
92
|
if persona is not None:
|
89
93
|
return f"{persona}\n{system_prompt}"
|
90
94
|
return system_prompt
|
@@ -100,17 +104,20 @@ class LLMConfig:
|
|
100
104
|
provider=self.get_default_model_provider(),
|
101
105
|
)
|
102
106
|
|
107
|
+
def set_default_persona(self, persona: str):
|
108
|
+
self._default_persona = persona
|
109
|
+
|
103
110
|
def set_default_system_prompt(self, system_prompt: str):
|
104
|
-
self.
|
111
|
+
self._default_system_prompt = system_prompt
|
105
112
|
|
106
113
|
def set_default_model_name(self, model_name: str):
|
107
|
-
self.
|
114
|
+
self._default_model_name = model_name
|
108
115
|
|
109
116
|
def set_default_model_api_key(self, model_api_key: str):
|
110
|
-
self.
|
117
|
+
self._default_model_api_key = model_api_key
|
111
118
|
|
112
119
|
def set_default_model_base_url(self, model_base_url: str):
|
113
|
-
self.
|
120
|
+
self._default_model_base_url = model_base_url
|
114
121
|
|
115
122
|
def set_default_provider(self, provider: Provider | str):
|
116
123
|
self._default_provider = provider
|
zrb/task/llm_task.py
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
import copy
|
1
2
|
import functools
|
2
3
|
import inspect
|
3
4
|
import json
|
@@ -6,6 +7,7 @@ import traceback
|
|
6
7
|
from collections.abc import Callable
|
7
8
|
from typing import Any
|
8
9
|
|
10
|
+
from openai import APIError
|
9
11
|
from pydantic_ai import Agent, Tool
|
10
12
|
from pydantic_ai.messages import (
|
11
13
|
FinalResultEvent,
|
@@ -139,16 +141,31 @@ class LLMTask(BaseTask):
|
|
139
141
|
history = await self._read_conversation_history(ctx)
|
140
142
|
user_prompt = self._get_message(ctx)
|
141
143
|
agent = self._get_agent(ctx)
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
144
|
+
try:
|
145
|
+
async with agent.iter(
|
146
|
+
user_prompt=user_prompt,
|
147
|
+
message_history=ModelMessagesTypeAdapter.validate_python(history),
|
148
|
+
) as agent_run:
|
149
|
+
async for node in agent_run:
|
150
|
+
# Each node represents a step in the agent's execution
|
151
|
+
# Reference: https://ai.pydantic.dev/agents/#streaming
|
152
|
+
try:
|
153
|
+
await self._print_node(ctx, agent_run, node)
|
154
|
+
except APIError as e:
|
155
|
+
# Extract detailed error information from the response
|
156
|
+
error_details = _extract_api_error_details(e)
|
157
|
+
ctx.log_error(f"API Error: {error_details}")
|
158
|
+
raise
|
159
|
+
except Exception as e:
|
160
|
+
ctx.log_error(f"Error processing node: {str(e)}")
|
161
|
+
ctx.log_error(f"Error type: {type(e).__name__}")
|
162
|
+
raise
|
163
|
+
new_history = json.loads(agent_run.result.all_messages_json())
|
164
|
+
await self._write_conversation_history(ctx, new_history)
|
165
|
+
return agent_run.result.data
|
166
|
+
except Exception as e:
|
167
|
+
ctx.log_error(f"Error in agent execution: {str(e)}")
|
168
|
+
raise
|
152
169
|
|
153
170
|
async def _print_node(self, ctx: AnyContext, agent_run: Any, node: Any):
|
154
171
|
if Agent.is_user_prompt_node(node):
|
@@ -204,9 +221,20 @@ class LLMTask(BaseTask):
|
|
204
221
|
async with node.stream(agent_run.ctx) as handle_stream:
|
205
222
|
async for event in handle_stream:
|
206
223
|
if isinstance(event, FunctionToolCallEvent):
|
207
|
-
#
|
208
|
-
if event.part.args == "":
|
224
|
+
# Handle empty arguments across different providers
|
225
|
+
if event.part.args == "" or event.part.args is None:
|
226
|
+
event.part.args = {}
|
227
|
+
elif isinstance(
|
228
|
+
event.part.args, str
|
229
|
+
) and event.part.args.strip() in ["null", "{}"]:
|
230
|
+
# Some providers might send "null" or "{}" as a string
|
209
231
|
event.part.args = {}
|
232
|
+
# Handle dummy property if present (from our schema sanitization)
|
233
|
+
if (
|
234
|
+
isinstance(event.part.args, dict)
|
235
|
+
and "_dummy" in event.part.args
|
236
|
+
):
|
237
|
+
del event.part.args["_dummy"]
|
210
238
|
ctx.print(
|
211
239
|
stylize_faint(
|
212
240
|
f"[Tools] The LLM calls tool={event.part.tool_name!r} with args={event.part.args} (tool_call_id={event.part.tool_call_id!r})" # noqa
|
@@ -330,13 +358,101 @@ class LLMTask(BaseTask):
|
|
330
358
|
|
331
359
|
|
332
360
|
def _wrap_tool(func):
|
333
|
-
|
334
|
-
|
361
|
+
sig = inspect.signature(func)
|
362
|
+
if len(sig.parameters) == 0:
|
363
|
+
|
364
|
+
@functools.wraps(func)
|
365
|
+
async def wrapper(_dummy=None):
|
366
|
+
try:
|
367
|
+
return await run_async(func())
|
368
|
+
except Exception as e:
|
369
|
+
# Optionally, you can include more details from traceback if needed.
|
370
|
+
error_details = traceback.format_exc()
|
371
|
+
return f"Error: {e}\nDetails: {error_details}"
|
372
|
+
|
373
|
+
new_sig = inspect.Signature(
|
374
|
+
parameters=[
|
375
|
+
inspect.Parameter(
|
376
|
+
"_dummy", inspect.Parameter.POSITIONAL_OR_KEYWORD, default=None
|
377
|
+
)
|
378
|
+
]
|
379
|
+
)
|
380
|
+
# Override the wrapper's signature so introspection yields a non-empty schema.
|
381
|
+
wrapper.__signature__ = new_sig
|
382
|
+
return wrapper
|
383
|
+
else:
|
384
|
+
|
385
|
+
@functools.wraps(func)
|
386
|
+
async def wrapper(*args, **kwargs):
|
387
|
+
try:
|
388
|
+
return await run_async(func(*args, **kwargs))
|
389
|
+
except Exception as e:
|
390
|
+
# Optionally, you can include more details from traceback if needed.
|
391
|
+
error_details = traceback.format_exc()
|
392
|
+
return f"Error: {e}\nDetails: {error_details}"
|
393
|
+
|
394
|
+
return wrapper
|
395
|
+
|
396
|
+
|
397
|
+
def _extract_api_error_details(error: APIError) -> str:
|
398
|
+
"""Extract detailed error information from an APIError."""
|
399
|
+
details = f"{error.message}"
|
400
|
+
# Try to parse the error body as JSON
|
401
|
+
if error.body:
|
335
402
|
try:
|
336
|
-
|
403
|
+
if isinstance(error.body, str):
|
404
|
+
body_json = json.loads(error.body)
|
405
|
+
elif isinstance(error.body, bytes):
|
406
|
+
body_json = json.loads(error.body.decode("utf-8"))
|
407
|
+
else:
|
408
|
+
body_json = error.body
|
409
|
+
# Extract error details from the JSON structure
|
410
|
+
if isinstance(body_json, dict):
|
411
|
+
if "error" in body_json:
|
412
|
+
error_obj = body_json["error"]
|
413
|
+
if isinstance(error_obj, dict):
|
414
|
+
if "message" in error_obj:
|
415
|
+
details += f"\nProvider message: {error_obj['message']}"
|
416
|
+
if "code" in error_obj:
|
417
|
+
details += f"\nError code: {error_obj['code']}"
|
418
|
+
if "status" in error_obj:
|
419
|
+
details += f"\nStatus: {error_obj['status']}"
|
420
|
+
# Check for metadata that might contain provider-specific information
|
421
|
+
if "metadata" in body_json and isinstance(body_json["metadata"], dict):
|
422
|
+
metadata = body_json["metadata"]
|
423
|
+
if "provider_name" in metadata:
|
424
|
+
details += f"\nProvider: {metadata['provider_name']}"
|
425
|
+
if "raw" in metadata:
|
426
|
+
try:
|
427
|
+
raw_json = json.loads(metadata["raw"])
|
428
|
+
if "error" in raw_json and isinstance(
|
429
|
+
raw_json["error"], dict
|
430
|
+
):
|
431
|
+
raw_error = raw_json["error"]
|
432
|
+
if "message" in raw_error:
|
433
|
+
details += (
|
434
|
+
f"\nRaw error message: {raw_error['message']}"
|
435
|
+
)
|
436
|
+
except (KeyError, TypeError, ValueError):
|
437
|
+
# If we can't parse the raw JSON, just include it as is
|
438
|
+
details += f"\nRaw error data: {metadata['raw']}"
|
439
|
+
except json.JSONDecodeError:
|
440
|
+
# If we can't parse the JSON, include the raw body
|
441
|
+
details += f"\nRaw error body: {error.body}"
|
337
442
|
except Exception as e:
|
338
|
-
#
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
443
|
+
# Catch any other exceptions during parsing
|
444
|
+
details += f"\nError parsing error body: {str(e)}"
|
445
|
+
# Include request information if available
|
446
|
+
if hasattr(error, "request") and error.request:
|
447
|
+
if hasattr(error.request, "method") and hasattr(error.request, "url"):
|
448
|
+
details += f"\nRequest: {error.request.method} {error.request.url}"
|
449
|
+
# Include a truncated version of the request content if available
|
450
|
+
if hasattr(error.request, "content") and error.request.content:
|
451
|
+
content = error.request.content
|
452
|
+
if isinstance(content, bytes):
|
453
|
+
try:
|
454
|
+
content = content.decode("utf-8")
|
455
|
+
except UnicodeDecodeError:
|
456
|
+
content = str(content)
|
457
|
+
details += f"\nRequest content: {content}"
|
458
|
+
return details
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: zrb
|
3
|
-
Version: 1.5.
|
3
|
+
Version: 1.5.3
|
4
4
|
Summary: Your Automation Powerhouse
|
5
5
|
Home-page: https://github.com/state-alchemists/zrb
|
6
6
|
License: AGPL-3.0-or-later
|
@@ -16,19 +16,18 @@ Classifier: Programming Language :: Python :: 3.12
|
|
16
16
|
Provides-Extra: all
|
17
17
|
Provides-Extra: playwright
|
18
18
|
Provides-Extra: rag
|
19
|
-
Requires-Dist:
|
20
|
-
Requires-Dist:
|
21
|
-
Requires-Dist:
|
22
|
-
Requires-Dist:
|
23
|
-
Requires-Dist:
|
24
|
-
Requires-Dist:
|
25
|
-
Requires-Dist:
|
26
|
-
Requires-Dist:
|
27
|
-
Requires-Dist:
|
28
|
-
Requires-Dist:
|
29
|
-
Requires-Dist:
|
30
|
-
Requires-Dist:
|
31
|
-
Requires-Dist: python-dotenv (>=1.0.1,<2.0.0)
|
19
|
+
Requires-Dist: beautifulsoup4 (>=4.13.3,<5.0.0)
|
20
|
+
Requires-Dist: black (>=25.1.0,<25.2.0)
|
21
|
+
Requires-Dist: chromadb (>=0.6.3,<0.7.0) ; extra == "rag" or extra == "all"
|
22
|
+
Requires-Dist: fastapi[standard] (>=0.115.12,<0.116.0)
|
23
|
+
Requires-Dist: isort (>=6.0.1,<6.1.0)
|
24
|
+
Requires-Dist: libcst (>=1.7.0,<2.0.0)
|
25
|
+
Requires-Dist: openai (>=1.70.0,<2.0.0) ; extra == "rag" or extra == "all"
|
26
|
+
Requires-Dist: pdfplumber (>=0.11.6,<0.12.0) ; extra == "rag" or extra == "all"
|
27
|
+
Requires-Dist: playwright (>=1.51.0,<2.0.0) ; extra == "playwright" or extra == "all"
|
28
|
+
Requires-Dist: psutil (>=7.0.0,<8.0.0)
|
29
|
+
Requires-Dist: pydantic-ai (>=0.0.49,<0.0.50)
|
30
|
+
Requires-Dist: python-dotenv (>=1.1.0,<2.0.0)
|
32
31
|
Requires-Dist: python-jose[cryptography] (>=3.4.0,<4.0.0)
|
33
32
|
Requires-Dist: requests (>=2.32.3,<3.0.0)
|
34
33
|
Requires-Dist: ulid-py (>=1.1.0,<2.0.0)
|
@@ -1,5 +1,5 @@
|
|
1
1
|
zrb/__init__.py,sha256=1waPjZcA3IHUEvIuVQso0YfNfW9i7SCJgEfzhiNTaCk,3020
|
2
|
-
zrb/__main__.py,sha256=
|
2
|
+
zrb/__main__.py,sha256=QJfEeJ-fsuxxb4md1BuAt7CX4jJmb8ttHf16bb2bf40,1768
|
3
3
|
zrb/attr/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
4
4
|
zrb/attr/type.py,sha256=4TV5gPYMMrKh5V-yB6iRYKCbsXAH_AvGXMsjxKLHcUs,568
|
5
5
|
zrb/builtin/__init__.py,sha256=oXG4Zm_rIp3G81Y7hiSe38jeS2sGZAnADoP_yxxhYEc,1926
|
@@ -21,7 +21,7 @@ zrb/builtin/project/add/fastapp/fastapp_task.py,sha256=z6hZ3j-dxUG7F3IH40rQAOvyh
|
|
21
21
|
zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/.coveragerc,sha256=MsTf0Vlt_pxV-j4mNh-TxSo7sTI_GaVS_oM4tksIykE,181
|
22
22
|
zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/.flake8,sha256=fgvHmuskgYiCvHZHaFtiyOWW0zasVrs0P-sFHOq3W5U,56
|
23
23
|
zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/.gitignore,sha256=D-ISOzaKlN_VzeZP5f8aznDSJX4p8PCtaK2JWM5yY1c,61
|
24
|
-
zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/README.md,sha256=
|
24
|
+
zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/README.md,sha256=xSOzXCovGHCJy62jr3a2DtbW4b0n8zB5ccGxhn7qKjs,6405
|
25
25
|
zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
26
26
|
zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/column/add_column_task.py,sha256=PxKS3azBnKMTZdStz1OTEr-7sCK_WMeCLiDd1gDoGHA,4819
|
27
27
|
zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/column/add_column_util.py,sha256=GycuEtcvO02OwqULfP-qRxnAnJDDhWx_hdRSmbfx5bo,10952
|
@@ -162,7 +162,7 @@ zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view
|
|
162
162
|
zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.yellow.min.css,sha256=mOkvNiE272UAgO8cVewJjU9BYidLxDZ97IcYodW--Ik,82218
|
163
163
|
zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/pico-css/pico.zinc.min.css,sha256=s8SdVQv4fX3W0LbfKDgUDczWcCyUfRbZhpyYtLdASC0,82212
|
164
164
|
zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/template/default.html,sha256=Lg4vONCLOx8PSORFitg8JZa-4dp-pyUvKSVzCJEFsB8,4048
|
165
|
-
zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/requirements.txt,sha256=
|
165
|
+
zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/requirements.txt,sha256=jSLXX-ZOElSG69qjx5yVcpg6X_QJoisNDUYpCv2ldH8,195
|
166
166
|
zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/schema/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
167
167
|
zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/schema/permission.py,sha256=q66LXdZ-QTb30F1VTXNLnjyYBlK_ThVLiHgavtJy4LY,1424
|
168
168
|
zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/schema/role.py,sha256=7USbuhHhPc3xXkmwiqTVKsN8-eFWS8Q7emKxCGNGPw0,3244
|
@@ -175,7 +175,7 @@ zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/test/auth/permissio
|
|
175
175
|
zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/test/auth/permission/test_update_permission.py,sha256=AHTUIX7cdR5tKkbxs6JVrp5uoeiwIvqaBrhLFGOYoFg,2498
|
176
176
|
zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/test/auth/test_user_session.py,sha256=RITk3KohVSEzdvyoOefzrx2eabHEhAx3eS3opjZwU5k,7096
|
177
177
|
zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/test/test_health_and_readiness.py,sha256=nqbRJtGQdaHsj3MqiFrUPpQteRBRPiyHp9dpdUZcMg0,823
|
178
|
-
zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/test/test_homepage.py,sha256=
|
178
|
+
zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/test/test_homepage.py,sha256=NnhAjs8JParlmTKynRb-l65h8FvEG_Tap5m8kDYvxOM,618
|
179
179
|
zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/test/test_not_found_error.py,sha256=SBqFRgGUldUtIz-uMf9a5DeWDPFeKbhvnvwiYr-jjns,502
|
180
180
|
zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/test.sh,sha256=QIwe6InrlEkmxdtj6NTO9JozeECYN0O4vx-x-qid6go,148
|
181
181
|
zrb/builtin/project/add/fastapp/fastapp_util.py,sha256=LfKcb_daaAdhMz0BgbYd1yIvw7DQzruZ7bjB7gLGFdk,1533
|
@@ -237,7 +237,7 @@ zrb/input/option_input.py,sha256=TQB82ko5odgzkULEizBZi0e9TIHEbIgvdP0AR3RhA74,213
|
|
237
237
|
zrb/input/password_input.py,sha256=szBojWxSP9QJecgsgA87OIYwQrY2AQ3USIKdDZY6snU,1465
|
238
238
|
zrb/input/str_input.py,sha256=NevZHX9rf1g8eMatPyy-kUX3DglrVAQpzvVpKAzf7bA,81
|
239
239
|
zrb/input/text_input.py,sha256=shvVbc2U8Is36h23M5lcW8IEwKc9FR-4uEPZZroj3rU,3377
|
240
|
-
zrb/llm_config.py,sha256=
|
240
|
+
zrb/llm_config.py,sha256=hVD6ohJdyYGbM-JBvBAStQvdUO251gKr-VKHxvK-RKs,4802
|
241
241
|
zrb/runner/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
242
242
|
zrb/runner/cli.py,sha256=0mT0oO_yEhc8N4nYCJNujhgLjVykZ0B-kAOFXyAvAqM,6672
|
243
243
|
zrb/runner/common_util.py,sha256=0zhZn1Jdmr194_nsL5_L-Kn9-_NDpMTI2z6_LXUQJ-U,1369
|
@@ -300,7 +300,7 @@ zrb/task/base_task.py,sha256=SQRf37bylS586KwyW0eYDe9JZ5Hl18FP8kScHae6y3A,21251
|
|
300
300
|
zrb/task/base_trigger.py,sha256=jC722rDvodaBLeNaFghkTyv1u0QXrK6BLZUUqcmBJ7Q,4581
|
301
301
|
zrb/task/cmd_task.py,sha256=pUKRSR4DZKjbmluB6vi7cxqyhxOLfJ2czSpYeQbiDvo,10705
|
302
302
|
zrb/task/http_check.py,sha256=Gf5rOB2Se2EdizuN9rp65HpGmfZkGc-clIAlHmPVehs,2565
|
303
|
-
zrb/task/llm_task.py,sha256=
|
303
|
+
zrb/task/llm_task.py,sha256=di9lYvcwd3uCPe9KzbDsXNy2ZJT49DmIIuYUS_bd8DY,19942
|
304
304
|
zrb/task/make_task.py,sha256=PD3b_aYazthS8LHeJsLAhwKDEgdurQZpymJDKeN60u0,2265
|
305
305
|
zrb/task/rsync_task.py,sha256=GSL9144bmp6F0EckT6m-2a1xG25AzrrWYzH4k3SVUKM,6370
|
306
306
|
zrb/task/scaffolder.py,sha256=rME18w1HJUHXgi9eTYXx_T2G4JdqDYzBoNOkdOOo5-o,6806
|
@@ -341,7 +341,7 @@ zrb/util/string/name.py,sha256=8picJfUBXNpdh64GNaHv3om23QHhUZux7DguFLrXHp8,1163
|
|
341
341
|
zrb/util/todo.py,sha256=1nDdwPc22oFoK_1ZTXyf3638Bg6sqE2yp_U4_-frHoc,16015
|
342
342
|
zrb/xcom/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
343
343
|
zrb/xcom/xcom.py,sha256=o79rxR9wphnShrcIushA0Qt71d_p3ZTxjNf7x9hJB78,1571
|
344
|
-
zrb-1.5.
|
345
|
-
zrb-1.5.
|
346
|
-
zrb-1.5.
|
347
|
-
zrb-1.5.
|
344
|
+
zrb-1.5.3.dist-info/METADATA,sha256=didD-AcEFyUlwOfXEyLCebJewXMt8hLRmLL1zp5HDZE,8470
|
345
|
+
zrb-1.5.3.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
346
|
+
zrb-1.5.3.dist-info/entry_points.txt,sha256=-Pg3ElWPfnaSM-XvXqCxEAa-wfVI6BEgcs386s8C8v8,46
|
347
|
+
zrb-1.5.3.dist-info/RECORD,,
|
File without changes
|
File without changes
|