flock-core 0.4.0b43__py3-none-any.whl → 0.4.0b45__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 flock-core might be problematic. Click here for more details.
- flock/cli/manage_agents.py +19 -4
- flock/core/api/__init__.py +1 -2
- flock/core/api/endpoints.py +150 -218
- flock/core/api/main.py +134 -653
- flock/core/api/service.py +214 -0
- flock/core/flock.py +192 -134
- flock/core/flock_agent.py +31 -0
- flock/webapp/app/api/agent_management.py +135 -164
- flock/webapp/app/api/execution.py +76 -85
- flock/webapp/app/api/flock_management.py +60 -33
- flock/webapp/app/chat.py +233 -0
- flock/webapp/app/config.py +6 -3
- flock/webapp/app/dependencies.py +95 -0
- flock/webapp/app/main.py +320 -906
- flock/webapp/app/services/flock_service.py +183 -161
- flock/webapp/run.py +176 -100
- flock/webapp/static/css/chat.css +227 -0
- flock/webapp/static/css/components.css +167 -0
- flock/webapp/static/css/header.css +39 -0
- flock/webapp/static/css/layout.css +46 -0
- flock/webapp/static/css/sidebar.css +127 -0
- flock/webapp/templates/base.html +6 -1
- flock/webapp/templates/chat.html +60 -0
- flock/webapp/templates/chat_settings.html +20 -0
- flock/webapp/templates/flock_editor.html +1 -1
- flock/webapp/templates/partials/_agent_detail_form.html +8 -7
- flock/webapp/templates/partials/_agent_list.html +3 -3
- flock/webapp/templates/partials/_agent_manager_view.html +3 -4
- flock/webapp/templates/partials/_chat_container.html +9 -0
- flock/webapp/templates/partials/_chat_messages.html +13 -0
- flock/webapp/templates/partials/_chat_settings_form.html +65 -0
- flock/webapp/templates/partials/_execution_form.html +2 -2
- flock/webapp/templates/partials/_execution_view_container.html +1 -1
- flock/webapp/templates/partials/_flock_properties_form.html +2 -2
- flock/webapp/templates/partials/_registry_viewer_content.html +3 -3
- flock/webapp/templates/partials/_sidebar.html +17 -1
- flock/webapp/templates/registry_viewer.html +3 -3
- {flock_core-0.4.0b43.dist-info → flock_core-0.4.0b45.dist-info}/METADATA +1 -1
- {flock_core-0.4.0b43.dist-info → flock_core-0.4.0b45.dist-info}/RECORD +42 -31
- flock/webapp/static/css/custom.css +0 -612
- flock/webapp/templates/partials/_agent_manager_view_old.html +0 -19
- {flock_core-0.4.0b43.dist-info → flock_core-0.4.0b45.dist-info}/WHEEL +0 -0
- {flock_core-0.4.0b43.dist-info → flock_core-0.4.0b45.dist-info}/entry_points.txt +0 -0
- {flock_core-0.4.0b43.dist-info → flock_core-0.4.0b45.dist-info}/licenses/LICENSE +0 -0
flock/webapp/run.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
# src/flock/webapp/run.py
|
|
2
2
|
import sys
|
|
3
3
|
from collections.abc import Callable, Sequence
|
|
4
4
|
from pathlib import Path
|
|
@@ -6,132 +6,208 @@ from typing import TYPE_CHECKING, Any
|
|
|
6
6
|
|
|
7
7
|
import uvicorn
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
# Import core Flock components
|
|
11
10
|
if TYPE_CHECKING:
|
|
12
|
-
from flock.core import
|
|
11
|
+
from flock.core.api.custom_endpoint import FlockEndpoint
|
|
12
|
+
from flock.core.flock import Flock
|
|
13
13
|
|
|
14
|
-
# ---
|
|
14
|
+
# --- Ensure src is in path for imports ---
|
|
15
|
+
current_file_path = Path(__file__).resolve()
|
|
16
|
+
flock_webapp_dir = current_file_path.parent
|
|
17
|
+
flock_dir = flock_webapp_dir.parent
|
|
18
|
+
src_dir = flock_dir.parent # Assuming `flock` is a package within `src`
|
|
15
19
|
|
|
20
|
+
if str(src_dir) not in sys.path:
|
|
21
|
+
sys.path.insert(0, str(src_dir))
|
|
16
22
|
|
|
17
|
-
|
|
23
|
+
# --- Main Server Startup Function ---
|
|
24
|
+
def start_unified_server(
|
|
18
25
|
flock_instance: "Flock",
|
|
19
26
|
host: str,
|
|
20
27
|
port: int,
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
28
|
+
server_title: str,
|
|
29
|
+
enable_ui_routes: bool,
|
|
30
|
+
enable_chat_routes: bool = False,
|
|
31
|
+
ui_theme: str | None = None,
|
|
32
|
+
custom_endpoints: Sequence["FlockEndpoint"] | dict[tuple[str, list[str] | None], Callable[..., Any]] | None = None,
|
|
24
33
|
):
|
|
25
|
-
"""Starts the
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
34
|
+
"""Starts the unified FastAPI server for Flock.
|
|
35
|
+
- Initializes the web application (imported from webapp.app.main).
|
|
36
|
+
- Sets the provided Flock instance and a RunStore for dependency injection
|
|
37
|
+
and makes them available via app.state.
|
|
38
|
+
- Configures the UI theme.
|
|
39
|
+
- Stores custom API endpoints for registration during app lifespan startup.
|
|
40
|
+
- Optionally registers chat routes.
|
|
41
|
+
- Runs Uvicorn.
|
|
42
|
+
"""
|
|
43
|
+
print(f"Attempting to start unified server for Flock '{flock_instance.name}' on http://{host}:{port}")
|
|
44
|
+
print(f"UI Routes Enabled: {enable_ui_routes}, Theme: {ui_theme or 'Default'}")
|
|
45
|
+
|
|
29
46
|
try:
|
|
30
|
-
#
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
# Import necessary webapp components *after* path setup
|
|
36
|
-
from flock.core.api.endpoints import (
|
|
37
|
-
create_api_router, # Need to adapt this later
|
|
38
|
-
)
|
|
39
|
-
from flock.core.api.main import FlockAPI
|
|
40
|
-
from flock.core.api.run_store import (
|
|
41
|
-
RunStore, # Needed for API routes later
|
|
42
|
-
)
|
|
43
|
-
from flock.webapp.app.config import (
|
|
47
|
+
# Import necessary webapp components HERE, after path setup.
|
|
48
|
+
from flock.core.api.run_store import RunStore
|
|
49
|
+
from flock.core.logging.logging import get_logger # For logging
|
|
50
|
+
from flock.webapp.app.config import ( # For logging resolved theme
|
|
44
51
|
get_current_theme_name,
|
|
45
52
|
set_current_theme_name,
|
|
46
53
|
)
|
|
47
|
-
from flock.webapp.app.
|
|
48
|
-
|
|
49
|
-
|
|
54
|
+
from flock.webapp.app.dependencies import (
|
|
55
|
+
add_pending_custom_endpoints,
|
|
56
|
+
set_global_flock_services,
|
|
50
57
|
)
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
set_current_theme_name(
|
|
54
|
-
theme_name
|
|
55
|
-
) # Uses default from config if theme_name is None
|
|
56
|
-
print(f"Integrated server using theme: {get_current_theme_name()}")
|
|
57
|
-
|
|
58
|
-
# 2. Set Flock Instance
|
|
59
|
-
set_current_flock_instance_programmatically(
|
|
60
|
-
flock_instance,
|
|
61
|
-
f"{flock_instance.name.replace(' ', '_').lower()}_integrated.flock",
|
|
58
|
+
from flock.webapp.app.main import (
|
|
59
|
+
app as fastapi_app, # The single FastAPI app instance
|
|
62
60
|
)
|
|
63
|
-
print(f"Flock '{flock_instance.name}' preloaded.")
|
|
64
|
-
|
|
65
|
-
flock_api = FlockAPI(flock_instance, custom_endpoints)
|
|
66
|
-
webapp_fastapi_app.include_router(flock_api.app.router, prefix="/api")
|
|
67
|
-
print("API routes included.")
|
|
68
61
|
|
|
69
|
-
|
|
70
|
-
|
|
62
|
+
logger = get_logger("webapp.run") # Use a logger
|
|
63
|
+
|
|
64
|
+
# 1. Set UI Theme globally for the webapp
|
|
65
|
+
set_current_theme_name(ui_theme)
|
|
66
|
+
logger.info(f"Unified server configured to use theme: {get_current_theme_name()}")
|
|
67
|
+
|
|
68
|
+
# 2. Create RunStore & Set Global Services for Dependency Injection
|
|
69
|
+
run_store_instance = RunStore()
|
|
70
|
+
set_global_flock_services(flock_instance, run_store_instance)
|
|
71
|
+
logger.info("Global Flock instance and RunStore set for dependency injection.")
|
|
72
|
+
|
|
73
|
+
# 3. Make Flock instance and filename available on app.state
|
|
74
|
+
fastapi_app.state.flock_instance = flock_instance
|
|
75
|
+
source_file_attr = "_source_file_path" # Attribute where Flock might store its load path
|
|
76
|
+
fastapi_app.state.flock_filename = getattr(flock_instance, source_file_attr, None) or \
|
|
77
|
+
f"{flock_instance.name.replace(' ', '_').lower()}.flock.yaml"
|
|
78
|
+
fastapi_app.state.run_store = run_store_instance
|
|
79
|
+
fastapi_app.state.chat_enabled = enable_chat_routes
|
|
80
|
+
|
|
81
|
+
logger.info(f"Flock '{flock_instance.name}' (from '{fastapi_app.state.flock_filename}') made available via app.state.")
|
|
82
|
+
|
|
83
|
+
# 4. Store Custom Endpoints for registration by the lifespan manager in app.main
|
|
84
|
+
processed_custom_endpoints = []
|
|
85
|
+
if custom_endpoints:
|
|
86
|
+
from flock.core.api.custom_endpoint import (
|
|
87
|
+
FlockEndpoint, # Ensure it's imported
|
|
88
|
+
)
|
|
89
|
+
if isinstance(custom_endpoints, dict):
|
|
90
|
+
for (path_val, methods_val), cb_val in custom_endpoints.items():
|
|
91
|
+
processed_custom_endpoints.append(
|
|
92
|
+
FlockEndpoint(path=path_val, methods=list(methods_val) if methods_val else ["GET"], callback=cb_val)
|
|
93
|
+
)
|
|
94
|
+
else: # Assumed Sequence[FlockEndpoint]
|
|
95
|
+
processed_custom_endpoints.extend(list(custom_endpoints))
|
|
96
|
+
|
|
97
|
+
if processed_custom_endpoints:
|
|
98
|
+
add_pending_custom_endpoints(processed_custom_endpoints)
|
|
99
|
+
logger.info(f"{len(processed_custom_endpoints)} custom endpoints stored for registration by app lifespan.")
|
|
100
|
+
|
|
101
|
+
# 5. Update FastAPI app title (FastAPI app instance is now imported from main)
|
|
102
|
+
fastapi_app.title = server_title
|
|
103
|
+
|
|
104
|
+
# 5a. Optionally strip UI routes if UI is disabled
|
|
105
|
+
if not enable_ui_routes:
|
|
106
|
+
from fastapi.routing import APIRoute
|
|
107
|
+
|
|
108
|
+
allowed_tags = {"Flock API Core", "Flock API Custom Endpoints", "Chat"}
|
|
109
|
+
|
|
110
|
+
def _route_is_allowed(route: APIRoute) -> bool: # type: ignore
|
|
111
|
+
# Keep documentation and non-API utility routes (no tags)
|
|
112
|
+
if not hasattr(route, "tags") or not route.tags:
|
|
113
|
+
return True
|
|
114
|
+
# Keep if any tag is in the allowed list
|
|
115
|
+
return any(tag in allowed_tags for tag in route.tags) # type: ignore
|
|
116
|
+
|
|
117
|
+
original_count = len(fastapi_app.router.routes)
|
|
118
|
+
fastapi_app.router.routes = [r for r in fastapi_app.router.routes if _route_is_allowed(r)]
|
|
119
|
+
|
|
120
|
+
# Clear cached OpenAPI schema so FastAPI regenerates it with the reduced route set
|
|
121
|
+
if hasattr(fastapi_app, "openapi_schema"):
|
|
122
|
+
fastapi_app.openapi_schema = None # type: ignore
|
|
123
|
+
|
|
124
|
+
logger.info(
|
|
125
|
+
f"UI disabled: removed {original_count - len(fastapi_app.router.routes)} UI routes. Remaining routes: {len(fastapi_app.router.routes)}"
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
# 5b. Include Chat routes if requested
|
|
129
|
+
if enable_chat_routes:
|
|
130
|
+
try:
|
|
131
|
+
from flock.webapp.app.chat import (
|
|
132
|
+
router as chat_router, # type: ignore
|
|
133
|
+
)
|
|
134
|
+
fastapi_app.include_router(chat_router, tags=["Chat"])
|
|
135
|
+
logger.info("Chat routes enabled and registered.")
|
|
136
|
+
except Exception as e:
|
|
137
|
+
logger.error(f"Failed to include chat routes: {e}")
|
|
138
|
+
|
|
139
|
+
# 6. Run Uvicorn
|
|
140
|
+
logger.info(f"Running Uvicorn with application: flock.webapp.app.main:app")
|
|
71
141
|
uvicorn.run(
|
|
72
|
-
|
|
73
|
-
|
|
142
|
+
"flock.webapp.app.main:app",
|
|
143
|
+
host=host,
|
|
144
|
+
port=port,
|
|
145
|
+
reload=False # Critical for programmatically set state like flock_instance
|
|
146
|
+
)
|
|
74
147
|
|
|
75
148
|
except ImportError as e:
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
)
|
|
80
|
-
print(
|
|
81
|
-
"Ensure all dependencies are installed and paths are correct.",
|
|
82
|
-
file=sys.stderr,
|
|
83
|
-
)
|
|
149
|
+
# More specific error logging
|
|
150
|
+
print(f"CRITICAL: Error importing components for unified server: {e}", file=sys.stderr)
|
|
151
|
+
print(f"Module not found: {e.name}", file=sys.stderr)
|
|
152
|
+
print("This usually means a problem with sys.path or missing dependencies.", file=sys.stderr)
|
|
153
|
+
print(f"Current sys.path: {sys.path}", file=sys.stderr)
|
|
84
154
|
sys.exit(1)
|
|
85
155
|
except Exception as e:
|
|
86
|
-
print(f"Error starting
|
|
156
|
+
print(f"CRITICAL: Error starting unified server: {e}", file=sys.stderr)
|
|
157
|
+
# Consider logging the full traceback for easier debugging
|
|
158
|
+
import traceback
|
|
159
|
+
traceback.print_exc(file=sys.stderr)
|
|
87
160
|
sys.exit(1)
|
|
88
161
|
|
|
89
162
|
|
|
90
|
-
# --- Standalone Webapp Runner (for `flock --web`) ---
|
|
163
|
+
# --- Standalone Webapp Runner (for `flock --web` or direct execution `python -m flock.webapp.run`) ---
|
|
164
|
+
def main():
|
|
165
|
+
"""Runs the Flock web application in standalone mode.
|
|
166
|
+
In this mode, no specific Flock is pre-loaded by the startup script;
|
|
167
|
+
the user will load or create one via the UI.
|
|
168
|
+
The FastAPI app (`webapp.app.main:app`) will initialize with DI services
|
|
169
|
+
set to None for Flock, and a new RunStore.
|
|
170
|
+
"""
|
|
171
|
+
print("Starting Flock web application in standalone mode...")
|
|
172
|
+
|
|
173
|
+
from flock.core.api.run_store import RunStore
|
|
174
|
+
from flock.webapp.app.config import (
|
|
175
|
+
get_current_theme_name, # To log the theme being used
|
|
176
|
+
)
|
|
177
|
+
from flock.webapp.app.dependencies import set_global_flock_services
|
|
91
178
|
|
|
179
|
+
# No pre-loaded Flock instance; create a RunStore so API calls can still function
|
|
180
|
+
standalone_run_store = RunStore()
|
|
181
|
+
set_global_flock_services(None, standalone_run_store)
|
|
92
182
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
print(f"Starting standalone webapp...")
|
|
98
|
-
# Ensure src is in path
|
|
99
|
-
src_dir = Path(__file__).resolve().parent.parent
|
|
100
|
-
if str(src_dir) not in sys.path:
|
|
101
|
-
sys.path.insert(0, str(src_dir))
|
|
183
|
+
print(
|
|
184
|
+
f"Standalone mode: Initialized global services. Flock: None, RunStore: {type(standalone_run_store)}"
|
|
185
|
+
)
|
|
186
|
+
print(f"Standalone webapp using theme: {get_current_theme_name()}")
|
|
102
187
|
|
|
188
|
+
host = "127.0.0.1"
|
|
189
|
+
port = 8344
|
|
103
190
|
try:
|
|
104
|
-
|
|
105
|
-
host = os.environ.get("FLOCK_WEB_HOST", "127.0.0.1")
|
|
106
|
-
port = int(os.environ.get("FLOCK_WEB_PORT", "8344"))
|
|
107
|
-
reload = os.environ.get("FLOCK_WEB_RELOAD", "true").lower() == "true"
|
|
108
|
-
# Use import string for app path
|
|
109
|
-
app_import_string = "flock.webapp.app.main:app"
|
|
110
|
-
|
|
111
|
-
# No need to import app instance here anymore for standalone mode
|
|
112
|
-
# from flock.webapp.app.main import app as webapp_fastapi_app
|
|
113
|
-
# from flock.webapp.app.config import get_current_theme_name
|
|
114
|
-
# print(f"Standalone webapp using theme: {get_current_theme_name()}") # Config now logs this on load
|
|
191
|
+
import os
|
|
115
192
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
193
|
+
host = os.environ.get("FLOCK_WEB_HOST", host)
|
|
194
|
+
port = int(os.environ.get("FLOCK_WEB_PORT", port))
|
|
195
|
+
webapp_reload = os.environ.get("FLOCK_WEB_RELOAD", "true").lower() == "true"
|
|
196
|
+
except Exception:
|
|
197
|
+
webapp_reload = True
|
|
198
|
+
|
|
199
|
+
app_import_string = "flock.webapp.app.main:app"
|
|
200
|
+
print(
|
|
201
|
+
f"Running Uvicorn: app='{app_import_string}', host='{host}', port={port}, reload={webapp_reload}"
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
uvicorn.run(
|
|
205
|
+
app_import_string,
|
|
206
|
+
host=host,
|
|
207
|
+
port=port,
|
|
208
|
+
reload=webapp_reload,
|
|
209
|
+
)
|
|
133
210
|
|
|
134
211
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
# The CLI entry point will call `main()` after potentially calling `set_initial_theme()`.
|
|
212
|
+
if __name__ == "__main__":
|
|
213
|
+
main()
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
/* --- Enhanced Chat Styles --- */
|
|
2
|
+
body.chat-page {
|
|
3
|
+
display: block;
|
|
4
|
+
padding: 0;
|
|
5
|
+
margin: 0;
|
|
6
|
+
height: 100vh;
|
|
7
|
+
width: 100vw;
|
|
8
|
+
overflow: hidden;
|
|
9
|
+
background-color: var(--pico-background-color);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
#chat-container {
|
|
13
|
+
/* Allow the chat container to grow to full width on small screens,
|
|
14
|
+
but cap it at 80% of the viewport on larger displays and
|
|
15
|
+
center it horizontally. */
|
|
16
|
+
width: 100%;
|
|
17
|
+
max-width: 80%;
|
|
18
|
+
margin: 0 auto;
|
|
19
|
+
display: flex;
|
|
20
|
+
flex-direction: column;
|
|
21
|
+
height: 100vh;
|
|
22
|
+
background-color: var(--pico-background-color);
|
|
23
|
+
overflow: hidden;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
#chat-log {
|
|
27
|
+
flex: 1;
|
|
28
|
+
overflow-y: auto;
|
|
29
|
+
padding: 1rem 1.5rem;
|
|
30
|
+
display: flex;
|
|
31
|
+
flex-direction: column;
|
|
32
|
+
min-height: 60vh;
|
|
33
|
+
gap: 1rem;
|
|
34
|
+
background-color: rgba(0, 0, 0, 0.05);
|
|
35
|
+
background-image:
|
|
36
|
+
radial-gradient(rgba(255, 255, 255, 0.03) 1px, transparent 1px),
|
|
37
|
+
radial-gradient(rgba(255, 255, 255, 0.03) 1px, transparent 1px);
|
|
38
|
+
background-size: 20px 20px;
|
|
39
|
+
background-position: 0 0, 10px 10px;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.bubble {
|
|
43
|
+
position: relative;
|
|
44
|
+
padding: 0.75rem 1rem;
|
|
45
|
+
border-radius: 1.2rem;
|
|
46
|
+
max-width: 80%;
|
|
47
|
+
margin: 0.25rem 0;
|
|
48
|
+
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
|
|
49
|
+
animation: fadeIn 0.3s ease-out;
|
|
50
|
+
word-break: break-word;
|
|
51
|
+
line-height: 1.4;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
@keyframes fadeIn {
|
|
55
|
+
from { opacity: 0; transform: translateY(10px); }
|
|
56
|
+
to { opacity: 1; transform: translateY(0); }
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.bubble.user {
|
|
60
|
+
background: var(--pico-primary);
|
|
61
|
+
color: var(--pico-button-base-color);
|
|
62
|
+
margin-left: auto;
|
|
63
|
+
border-bottom-right-radius: 0.3rem;
|
|
64
|
+
text-align: right;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.bubble.user::after {
|
|
68
|
+
content: '';
|
|
69
|
+
position: absolute;
|
|
70
|
+
bottom: 0;
|
|
71
|
+
right: -0.5rem;
|
|
72
|
+
width: 1rem;
|
|
73
|
+
height: 1rem;
|
|
74
|
+
background: var(--pico-primary-hover, var(--pico-primary));
|
|
75
|
+
clip-path: polygon(0 0, 0% 100%, 100% 100%);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.bubble.bot {
|
|
79
|
+
background: var(--pico-code-background-color);
|
|
80
|
+
color: var(--pico-code-color);
|
|
81
|
+
margin-right: auto;
|
|
82
|
+
border-bottom-left-radius: 0.3rem;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.bubble.bot::after {
|
|
86
|
+
content: '';
|
|
87
|
+
position: absolute;
|
|
88
|
+
bottom: 0;
|
|
89
|
+
left: -0.5rem;
|
|
90
|
+
width: 1rem;
|
|
91
|
+
height: 1rem;
|
|
92
|
+
background: var(--pico-code-background-color);
|
|
93
|
+
clip-path: polygon(100% 0, 0% 100%, 100% 100%);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
#chat-container form {
|
|
97
|
+
display: flex;
|
|
98
|
+
gap: 0.5rem;
|
|
99
|
+
margin: 0;
|
|
100
|
+
padding: 1rem;
|
|
101
|
+
background-color: var(--pico-card-background-color);
|
|
102
|
+
border-top: 1px solid var(--pico-muted-border-color);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
#chat-container form input[type="text"] {
|
|
106
|
+
flex: 1;
|
|
107
|
+
border-radius: 2rem;
|
|
108
|
+
padding-left: 1.25rem;
|
|
109
|
+
background-color: var(--pico-background-color);
|
|
110
|
+
border: 1px solid var(--pico-muted-border-color);
|
|
111
|
+
transition: all 0.2s ease;
|
|
112
|
+
height: 3rem;
|
|
113
|
+
font-size: 1rem;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
#chat-container form input[type="text"]:focus {
|
|
117
|
+
border-color: var(--pico-primary);
|
|
118
|
+
box-shadow: 0 0 0 2px rgba(var(--pico-primary-rgb, 0, 123, 255), 0.25);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
#chat-form button {
|
|
122
|
+
flex: 0 0 auto;
|
|
123
|
+
min-width: auto;
|
|
124
|
+
width: 150px; /* Wider send button */
|
|
125
|
+
padding: 0 1rem;
|
|
126
|
+
border-radius: 2rem;
|
|
127
|
+
background: var(--pico-primary);
|
|
128
|
+
color: var(--pico-button-base-color);
|
|
129
|
+
font-weight: 600;
|
|
130
|
+
transition: all 0.2s ease;
|
|
131
|
+
margin-left: 0.5rem;
|
|
132
|
+
height: 3rem;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
#chat-form button:hover {
|
|
136
|
+
background: var(--pico-primary-hover, var(--pico-primary));
|
|
137
|
+
transform: translateY(-2px);
|
|
138
|
+
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
.chat-header {
|
|
142
|
+
padding: 1rem 1.5rem;
|
|
143
|
+
background-color: var(--pico-card-background-color);
|
|
144
|
+
border-bottom: 1px solid var(--pico-muted-border-color);
|
|
145
|
+
display: flex;
|
|
146
|
+
align-items: center;
|
|
147
|
+
justify-content: space-between;
|
|
148
|
+
flex-shrink: 0;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.chat-header h2 {
|
|
152
|
+
margin: 0;
|
|
153
|
+
font-size: 1.5rem;
|
|
154
|
+
color: var(--pico-color);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
.chat-header h3 {
|
|
158
|
+
margin: 0;
|
|
159
|
+
font-size: 0.9rem;
|
|
160
|
+
color: var(--pico-muted-color);
|
|
161
|
+
font-weight: normal;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
.chat-timestamp {
|
|
165
|
+
display: block;
|
|
166
|
+
font-size: 0.7rem;
|
|
167
|
+
color: var(--pico-button-base-color);
|
|
168
|
+
margin-top: 0.25rem;
|
|
169
|
+
opacity: 0.8;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
.chat-footer {
|
|
173
|
+
padding: 0.5rem 1rem;
|
|
174
|
+
text-align: center;
|
|
175
|
+
font-size: 0.8rem;
|
|
176
|
+
color: var(--pico-muted-color);
|
|
177
|
+
background-color: var(--pico-card-background-color);
|
|
178
|
+
border-top: 1px solid var(--pico-muted-border-color);
|
|
179
|
+
flex-shrink: 0;
|
|
180
|
+
}
|
|
181
|
+
/* --- End Enhanced Chat Styles --- */
|
|
182
|
+
|
|
183
|
+
/* -------------------------------------------------------------------------
|
|
184
|
+
Chat container tweaks when embedded in the main UI (non-standalone mode)
|
|
185
|
+
------------------------------------------------------------------------- */
|
|
186
|
+
body:not(.chat-page) #chat-container,
|
|
187
|
+
body:not(.chat-page) .chat-container {
|
|
188
|
+
height: auto;
|
|
189
|
+
min-height: 60vh;
|
|
190
|
+
/* share same centering rules */
|
|
191
|
+
width: 100%;
|
|
192
|
+
max-width: 80%;
|
|
193
|
+
margin: 0 auto;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/* Settings form inside chat container should stack vertically */
|
|
197
|
+
.chat-settings-form {
|
|
198
|
+
display: flex;
|
|
199
|
+
flex-direction: column;
|
|
200
|
+
min-height: 60vh;
|
|
201
|
+
min-width: 100%;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
.chat-settings-form label,
|
|
205
|
+
.chat-settings-form input,
|
|
206
|
+
.chat-settings-form select {
|
|
207
|
+
display: block;
|
|
208
|
+
width: 100%;
|
|
209
|
+
margin-bottom: 0.75rem;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
.chat-settings-form .grid {
|
|
213
|
+
display: flex;
|
|
214
|
+
gap: 0.5rem;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/* Button sizing for Save Settings */
|
|
218
|
+
.chat-settings-form .grid button:first-child {
|
|
219
|
+
flex: 1 1 auto; /* expand in standalone */
|
|
220
|
+
width: 50%;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/* In integrated UI (non chat-page) keep natural size */
|
|
224
|
+
body:not(.chat-page) .chat-settings-form .grid button:first-child {
|
|
225
|
+
flex: 0 0 auto;
|
|
226
|
+
width: auto;
|
|
227
|
+
}
|