mindroot 9.3.0__py3-none-any.whl → 9.5.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 (183) hide show
  1. mindroot/coreplugins/admin/__init__.py +3 -1
  2. mindroot/coreplugins/admin/agent_router.py +250 -7
  3. mindroot/coreplugins/admin/asset_manager.py +164 -0
  4. mindroot/coreplugins/admin/command_router.py +236 -1
  5. mindroot/coreplugins/admin/mcp_catalog_routes.py +156 -0
  6. mindroot/coreplugins/admin/mcp_publish_routes.py +450 -0
  7. mindroot/coreplugins/admin/mcp_registry_routes.py +495 -0
  8. mindroot/coreplugins/admin/mcp_routes.py +216 -0
  9. mindroot/coreplugins/admin/mod.py +62 -0
  10. mindroot/coreplugins/admin/oauth_callback_router.py +84 -0
  11. mindroot/coreplugins/admin/persona_handler.py +15 -6
  12. mindroot/coreplugins/admin/persona_router.py +158 -2
  13. mindroot/coreplugins/admin/plugin_manager.py +63 -0
  14. mindroot/coreplugins/admin/plugin_router_fixed.py +23 -0
  15. mindroot/coreplugins/admin/plugin_router_new_not_working.py +145 -0
  16. mindroot/coreplugins/admin/plugin_routes.py +114 -0
  17. mindroot/coreplugins/admin/registry_settings_routes.py +140 -0
  18. mindroot/coreplugins/admin/router.py +116 -15
  19. mindroot/coreplugins/admin/service_models.py +1 -1
  20. mindroot/coreplugins/admin/settings_router.py +1 -0
  21. mindroot/coreplugins/admin/static/css/admin-custom.css +357 -2
  22. mindroot/coreplugins/admin/static/css/dark.css +1 -0
  23. mindroot/coreplugins/admin/static/css/default.css +4 -0
  24. mindroot/coreplugins/admin/static/js/about-info.js +367 -0
  25. mindroot/coreplugins/admin/static/js/agent-form.js +83 -3
  26. mindroot/coreplugins/admin/static/js/api-key-script.js +307 -0
  27. mindroot/coreplugins/admin/static/js/mcp-manager.js +348 -0
  28. mindroot/coreplugins/admin/static/js/mcp-publisher.js +780 -0
  29. mindroot/coreplugins/admin/static/js/persona-editor.js +34 -5
  30. mindroot/coreplugins/admin/static/js/plugin-toggle.js +1 -1
  31. mindroot/coreplugins/admin/static/js/recommended-plugin-install.js +63 -0
  32. mindroot/coreplugins/admin/static/js/registry-auth-section.js +132 -0
  33. mindroot/coreplugins/admin/static/js/registry-manager-base.js +613 -0
  34. mindroot/coreplugins/admin/static/js/registry-manager-old.js +385 -0
  35. mindroot/coreplugins/admin/static/js/registry-manager-publish-old-delete.js +166 -0
  36. mindroot/coreplugins/admin/static/js/registry-manager.js +351 -0
  37. mindroot/coreplugins/admin/static/js/registry-publish-section.js +377 -0
  38. mindroot/coreplugins/admin/static/js/registry-search-section.js +400 -0
  39. mindroot/coreplugins/admin/static/js/registry-search-section.js.bak +3 -0
  40. mindroot/coreplugins/admin/static/js/registry-settings.js +69 -0
  41. mindroot/coreplugins/admin/static/js/registry-shared-services.js +857 -0
  42. mindroot/coreplugins/admin/static/js/registry-simple-sections.js +85 -0
  43. mindroot/coreplugins/admin/static/js/secure-widget-manager.js +438 -0
  44. mindroot/coreplugins/admin/static/logo.png +0 -0
  45. mindroot/coreplugins/admin/templates/admin.jinja2 +275 -110
  46. mindroot/coreplugins/agent/Assistant/agent.json +27 -11
  47. mindroot/coreplugins/agent/agent.py +2 -2
  48. mindroot/coreplugins/agent/command_parser.py +25 -10
  49. mindroot/coreplugins/agent/templates/system.jinja2 +0 -12
  50. mindroot/coreplugins/chat/__init__.py +4 -1
  51. mindroot/coreplugins/chat/router.py +132 -20
  52. mindroot/coreplugins/chat/router_dedup_patch.py +20 -0
  53. mindroot/coreplugins/chat/services.py +31 -1
  54. mindroot/coreplugins/chat/static/css/action-fix.css +32 -0
  55. mindroot/coreplugins/chat/static/css/admin-custom.css +5 -3
  56. mindroot/coreplugins/chat/static/css/dark.css +24 -3
  57. mindroot/coreplugins/chat/static/css/default.css +24 -3
  58. mindroot/coreplugins/chat/static/css/main.css +1 -0
  59. mindroot/coreplugins/chat/static/js/action.js +137 -60
  60. mindroot/coreplugins/chat/static/js/chat-history.js +3 -0
  61. mindroot/coreplugins/chat/static/js/chat.js +59 -16
  62. mindroot/coreplugins/chat/static/js/chat.js.diff +221 -0
  63. mindroot/coreplugins/chat/static/js/chatform.js +2 -2
  64. mindroot/coreplugins/chat/static/site.webmanifest +1 -1
  65. mindroot/coreplugins/chat/templates/chat.jinja2 +3 -3
  66. mindroot/coreplugins/chat/widget_manager.py +139 -0
  67. mindroot/coreplugins/chat/widget_routes.py +287 -0
  68. mindroot/coreplugins/check_list/inject/admin.jinja2 +1 -1
  69. mindroot/coreplugins/email/__init__.py +2 -0
  70. mindroot/coreplugins/email/email_provider.py +2 -2
  71. mindroot/coreplugins/email/mod.py +100 -0
  72. mindroot/coreplugins/email/services.py +5 -3
  73. mindroot/coreplugins/email/smtp_handler.py +9 -3
  74. mindroot/coreplugins/email/test_email_service.py +75 -0
  75. mindroot/coreplugins/env_manager/mod.py +61 -25
  76. mindroot/coreplugins/home/router.py +37 -2
  77. mindroot/coreplugins/home/static/imgs/logo.png +0 -0
  78. mindroot/coreplugins/home/static/imgs/logo.png.bak +0 -0
  79. mindroot/coreplugins/home/static/imgs/logo_teal.png +0 -0
  80. mindroot/coreplugins/home/static/imgs/logo_teal2.png +0 -0
  81. mindroot/coreplugins/home/static/imgs/logo_teal_detailed.png +0 -0
  82. mindroot/coreplugins/home/static/imgs/logo_teal_python.png +0 -0
  83. mindroot/coreplugins/home/templates/home.jinja2 +15 -6
  84. mindroot/coreplugins/index/indices/default/index.json +6 -6
  85. mindroot/coreplugins/jwt_auth/middleware.py +47 -2
  86. mindroot/coreplugins/jwt_auth/mod.py +40 -17
  87. mindroot/coreplugins/l8n/__init__.py +6 -0
  88. mindroot/coreplugins/l8n/debug_loader.py +85 -0
  89. mindroot/coreplugins/l8n/debug_middleware.py +74 -0
  90. mindroot/coreplugins/l8n/l8n_constants.py +19 -0
  91. mindroot/coreplugins/l8n/language_detection.py +183 -0
  92. mindroot/coreplugins/l8n/middleware.py +151 -0
  93. mindroot/coreplugins/l8n/mod.py +277 -0
  94. mindroot/coreplugins/l8n/monkey_patch_to_delete.py +186 -0
  95. mindroot/coreplugins/l8n/test_enhanced.py +298 -0
  96. mindroot/coreplugins/l8n/test_l8n.py +95 -0
  97. mindroot/coreplugins/l8n/test_l8n_standalone.py +251 -0
  98. mindroot/coreplugins/l8n/test_middleware.py +272 -0
  99. mindroot/coreplugins/l8n/utils.py +232 -0
  100. mindroot/coreplugins/mcp_/__init__.py +14 -0
  101. mindroot/coreplugins/mcp_/catalog_commands.py +328 -0
  102. mindroot/coreplugins/mcp_/catalog_manager.py +263 -0
  103. mindroot/coreplugins/mcp_/dynamic_commands.py +154 -0
  104. mindroot/coreplugins/mcp_/mcp_manager.py +1031 -0
  105. mindroot/coreplugins/mcp_/mod.py +367 -0
  106. mindroot/coreplugins/mcp_/oauth_storage.py +144 -0
  107. mindroot/coreplugins/mcp_/server_installer.py +79 -0
  108. mindroot/coreplugins/mcp_/setup.py +26 -0
  109. mindroot/coreplugins/mcp_/test_dynamic_commands.py +134 -0
  110. mindroot/coreplugins/mcp_/testmcpclient.py +92 -0
  111. mindroot/coreplugins/persona/mod.py +12 -7
  112. mindroot/coreplugins/signup/templates/signup.jinja2 +1 -1
  113. mindroot/coreplugins/subscriptions/__init__.py +1 -0
  114. mindroot/coreplugins/subscriptions/mod.py +14 -3
  115. mindroot/coreplugins/subscriptions/router.py +3 -0
  116. mindroot/coreplugins/user_service/__init__.py +1 -2
  117. mindroot/coreplugins/user_service/admin_init.py +1 -0
  118. mindroot/coreplugins/user_service/email_service.py +72 -17
  119. mindroot/coreplugins/user_service/mod.py +10 -2
  120. mindroot/coreplugins/user_service/router.py +2 -0
  121. mindroot/lib/auth/api_key.py +28 -0
  122. mindroot/lib/cli/plugins.py +94 -0
  123. mindroot/lib/plugins/default_plugin_manifest.json +20 -0
  124. mindroot/lib/plugins/installation.py +5 -5
  125. mindroot/lib/plugins/l8n_static_handler.py +225 -0
  126. mindroot/lib/plugins/loader.py +33 -3
  127. mindroot/lib/plugins/loader_with_l8n.py +281 -0
  128. mindroot/lib/plugins/manifest.py +236 -24
  129. mindroot/lib/providers/commands.py +3 -1
  130. mindroot/lib/route_decorators.py +5 -5
  131. mindroot/lib/templates.py +183 -11
  132. mindroot/lib/utils/merge_arrays.py +1 -1
  133. mindroot/migrate.py +39 -20
  134. mindroot/registry/data_access.py +1 -1
  135. mindroot/server.py +42 -13
  136. mindroot/server_missing_normal_args.py +197 -0
  137. mindroot/server_prev.py +173 -0
  138. {mindroot-9.3.0.dist-info → mindroot-9.5.0.dist-info}/METADATA +7 -2
  139. {mindroot-9.3.0.dist-info → mindroot-9.5.0.dist-info}/RECORD +144 -112
  140. mindroot/coreplugins/admin/static/favicon/about.txt +0 -6
  141. mindroot/coreplugins/admin/static/favicon/android-chrome-512x512.png +0 -0
  142. mindroot/coreplugins/admin/static/favicon/apple-touch-icon.png +0 -0
  143. mindroot/coreplugins/admin/static/favicon/favicon-16x16.png +0 -0
  144. mindroot/coreplugins/admin/static/favicon/favicon-32x32.png +0 -0
  145. mindroot/coreplugins/admin/static/favicon/favicon.ico +0 -0
  146. mindroot/coreplugins/admin/static/favicon/favicon_io (1)/about.txt +0 -6
  147. mindroot/coreplugins/admin/static/favicon/favicon_io (1)/android-chrome-192x192.png +0 -0
  148. mindroot/coreplugins/admin/static/favicon/favicon_io (1)/android-chrome-512x512.png +0 -0
  149. mindroot/coreplugins/admin/static/favicon/favicon_io (1)/apple-touch-icon.png +0 -0
  150. mindroot/coreplugins/admin/static/favicon/favicon_io (1)/favicon-16x16.png +0 -0
  151. mindroot/coreplugins/admin/static/favicon/favicon_io (1)/favicon-32x32.png +0 -0
  152. mindroot/coreplugins/admin/static/favicon/favicon_io (1)/favicon.ico +0 -0
  153. mindroot/coreplugins/admin/static/favicon/favicon_io (1)/site.webmanifest +0 -1
  154. mindroot/coreplugins/admin/static/favicon/logo.png +0 -0
  155. mindroot/coreplugins/admin/static/favicon/site.webmanifest +0 -1
  156. mindroot/coreplugins/admin/static/js/backup/agent-editor.js +0 -186
  157. mindroot/coreplugins/admin/static/js/backup/agent-form.js +0 -1133
  158. mindroot/coreplugins/admin/static/js/backup/agent-list.js +0 -94
  159. mindroot/coreplugins/chat/static/favicon/about.txt +0 -6
  160. mindroot/coreplugins/chat/static/favicon/android-chrome-192x192.png +0 -0
  161. mindroot/coreplugins/chat/static/favicon/android-chrome-512x512.png +0 -0
  162. mindroot/coreplugins/chat/static/favicon/apple-touch-icon.png +0 -0
  163. mindroot/coreplugins/chat/static/favicon/favicon-16x16.png +0 -0
  164. mindroot/coreplugins/chat/static/favicon/favicon-32x32.png +0 -0
  165. mindroot/coreplugins/chat/static/favicon/favicon.ico +0 -0
  166. mindroot/coreplugins/chat/static/favicon/favicon_io (1)/about.txt +0 -6
  167. mindroot/coreplugins/chat/static/favicon/favicon_io (1)/android-chrome-192x192.png +0 -0
  168. mindroot/coreplugins/chat/static/favicon/favicon_io (1)/android-chrome-512x512.png +0 -0
  169. mindroot/coreplugins/chat/static/favicon/favicon_io (1)/apple-touch-icon.png +0 -0
  170. mindroot/coreplugins/chat/static/favicon/favicon_io (1)/favicon-16x16.png +0 -0
  171. mindroot/coreplugins/chat/static/favicon/favicon_io (1)/favicon-32x32.png +0 -0
  172. mindroot/coreplugins/chat/static/favicon/favicon_io (1)/favicon.ico +0 -0
  173. mindroot/coreplugins/chat/static/favicon/favicon_io (1)/site.webmanifest +0 -1
  174. mindroot/coreplugins/chat/static/favicon/logo.png +0 -0
  175. mindroot/coreplugins/chat/static/favicon/site.webmanifest +0 -1
  176. mindroot/coreplugins/index/default.json +0 -76
  177. mindroot/coreplugins/user_service/file_trigger_service.py +0 -12
  178. mindroot/coreplugins/user_service/hooks.py +0 -23
  179. /mindroot/coreplugins/{admin/static/favicon/android-chrome-192x192.png → home/static/imgs/backuplogo.png} +0 -0
  180. {mindroot-9.3.0.dist-info → mindroot-9.5.0.dist-info}/WHEEL +0 -0
  181. {mindroot-9.3.0.dist-info → mindroot-9.5.0.dist-info}/entry_points.txt +0 -0
  182. {mindroot-9.3.0.dist-info → mindroot-9.5.0.dist-info}/licenses/LICENSE +0 -0
  183. {mindroot-9.3.0.dist-info → mindroot-9.5.0.dist-info}/top_level.txt +0 -0
@@ -1,4 +1,7 @@
1
- # This file is required to make Python treat the directory as a package.
1
+ # This file is required to make Python treat the directory as a package.
2
2
  from .mod import *
3
3
  from .services import *
4
4
  from .commands import *
5
+
6
+ # Import widget manager to ensure it's loaded
7
+ from .widget_manager import widget_manager
@@ -1,5 +1,5 @@
1
- from fastapi import APIRouter, HTTPException, Request, Response, Depends
2
- from fastapi.responses import HTMLResponse, RedirectResponse
1
+ from fastapi import APIRouter, HTTPException, Request, Response, Depends, Query
2
+ from fastapi.responses import HTMLResponse, RedirectResponse, JSONResponse
3
3
  from fastapi import File, UploadFile, Form
4
4
  from sse_starlette.sse import EventSourceResponse
5
5
  from .models import MessageParts
@@ -22,6 +22,7 @@ import json
22
22
  from lib.chatcontext import ChatContext
23
23
  import shutil
24
24
  from pydantic import BaseModel
25
+ from lib.auth.api_key import verify_api_key
25
26
 
26
27
  router = APIRouter()
27
28
 
@@ -52,20 +53,38 @@ async def context1(request: Request, log_id: str):
52
53
  print(context)
53
54
  return "ok"
54
55
 
55
- @router.get("/context2/{log_id}")
56
- async def context2(request: Request, log_id: str):
57
- user = request.state.user.username
58
- context = await get_context(log_id, user)
59
- print(context)
60
- return "ok"
61
56
 
62
-
63
- # need to serve persona images from ./personas/local/[persona_name]/avatar.png
64
- @router.get("/chat/personas/{persona_name}/avatar.png")
65
- async def get_persona_avatar(persona_name: str):
66
- file_path = f"personas/local/{persona_name}/avatar.png"
57
+ # need to serve persona images from ./personas/local/[persona_path]/avatar.png
58
+ @router.get("/chat/personas/{persona_path:path}/avatar.png")
59
+ async def get_persona_avatar(persona_path: str):
60
+ # Check if this is a registry persona with deduplicated assets
61
+ if persona_path.startswith("registry/"):
62
+ persona_json_path = f"personas/{persona_path}/persona.json"
63
+ if os.path.exists(persona_json_path):
64
+ try:
65
+ with open(persona_json_path, "r") as f:
66
+ persona_data = json.load(f)
67
+
68
+ # Check if persona has asset hashes (deduplicated storage)
69
+ asset_hashes = persona_data.get("asset_hashes", {})
70
+ if "avatar" in asset_hashes:
71
+ # Redirect to deduplicated asset endpoint
72
+ return RedirectResponse(f"/assets/{asset_hashes['avatar']}")
73
+ except Exception as e:
74
+ print(f"Error checking for deduplicated assets: {e}")
75
+
76
+ # Handle registry personas: registry/owner/name
77
+ if persona_path.startswith('registry/'):
78
+ file_path = f"personas/{persona_path}/avatar.png"
79
+ else:
80
+ # Legacy support: check local first, then shared
81
+ file_path = f"personas/local/{persona_path}/avatar.png"
82
+ if not os.path.exists(file_path):
83
+ file_path = f"personas/registry/{persona_path}/avatar.png"
84
+
67
85
  if not os.path.exists(file_path):
68
- return {"error": "File not found"}
86
+ resolved = os.path.realpath(file_path)
87
+ return {"error": "File not found: " + resolved}
69
88
 
70
89
  with open(file_path, "rb") as f:
71
90
  image_bytes = f.read()
@@ -79,6 +98,48 @@ async def get_persona_avatar(persona_name: str):
79
98
  }
80
99
  )
81
100
 
101
+ @router.get("/chat/personas/{persona_path:path}/faceref.png")
102
+ async def get_persona_faceref(persona_path: str):
103
+ # Check if this is a registry persona with deduplicated assets
104
+ if persona_path.startswith("registry/"):
105
+ persona_json_path = f"personas/{persona_path}/persona.json"
106
+ if os.path.exists(persona_json_path):
107
+ try:
108
+ with open(persona_json_path, "r") as f:
109
+ persona_data = json.load(f)
110
+
111
+ # Check if persona has asset hashes (deduplicated storage)
112
+ asset_hashes = persona_data.get("asset_hashes", {})
113
+ if "faceref" in asset_hashes:
114
+ # Redirect to deduplicated asset endpoint
115
+ return RedirectResponse(f"/assets/{asset_hashes['faceref']}")
116
+ except Exception as e:
117
+ print(f"Error checking for deduplicated assets: {e}")
118
+
119
+ # Handle registry personas: registry/owner/name
120
+ if persona_path.startswith('registry/'):
121
+ file_path = f"personas/{persona_path}/faceref.png"
122
+ else:
123
+ # Legacy support: check local first, then shared
124
+ file_path = f"personas/local/{persona_path}/faceref.png"
125
+ if not os.path.exists(file_path):
126
+ file_path = f"personas/registry/{persona_path}/faceref.png"
127
+
128
+ if not os.path.exists(file_path):
129
+ # Fallback to avatar if faceref doesn't exist
130
+ return RedirectResponse(f"/chat/personas/{persona_path}/avatar.png")
131
+
132
+ with open(file_path, "rb") as f:
133
+ image_bytes = f.read()
134
+
135
+ return Response(
136
+ content=image_bytes,
137
+ media_type="image/png",
138
+ headers={
139
+ "Cache-Control": "max-age=3600",
140
+ "Content-Disposition": "inline; filename=faceref.png"
141
+ }
142
+ )
82
143
 
83
144
  @router.get("/chat/{log_id}/events")
84
145
  async def chat_events(log_id: str):
@@ -103,8 +164,26 @@ async def send_message(request: Request, log_id: str, message_parts: List[Messag
103
164
  return {"status": "ok", "task_id": task_id}
104
165
 
105
166
  @router.get("/agent/{agent_name}", response_class=HTMLResponse)
106
- async def get_chat_html(request: Request, agent_name: str):
107
- user = request.state.user
167
+ async def get_chat_html(request: Request, agent_name: str, api_key: str = Query(None), embed: bool = Query(False)):
168
+ # Handle API key authentication if provided
169
+ if api_key:
170
+ try:
171
+ user_data = await verify_api_key(api_key)
172
+ if not user_data:
173
+ raise HTTPException(status_code=401, detail="Invalid API key")
174
+ # Create a mock user object for API key users
175
+ class MockUser:
176
+ def __init__(self, username):
177
+ self.username = username
178
+ user = MockUser(user_data['username'])
179
+ except Exception as e:
180
+ raise HTTPException(status_code=401, detail="Invalid API key")
181
+ else:
182
+ # Use regular authentication
183
+ if not hasattr(request.state, "user"):
184
+ return RedirectResponse("/login")
185
+ user = request.state.user
186
+
108
187
  log_id = nanoid.generate()
109
188
  plugins = list_enabled()
110
189
  print("Init chat with user", user)
@@ -119,9 +198,28 @@ async def get_chat_html(request: Request, agent_name: str):
119
198
  debug_box("Access token saved to session file")
120
199
  else:
121
200
  debug_box("No access token found in request state")
122
-
201
+
202
+ # If embed mode is requested, redirect to embed session
203
+ if embed:
204
+ return RedirectResponse(f"/session/{agent_name}/{log_id}?embed=true")
205
+
206
+ # Regular redirect
123
207
  return RedirectResponse(f"/session/{agent_name}/{log_id}")
124
208
 
209
+ @router.get("/makesession/{agent_name}")
210
+ async def make_session(request: Request, agent_name: str):
211
+ """
212
+ Create a new chat session for the specified agent.
213
+ Returns a redirect to the chat session page.
214
+ """
215
+ if not hasattr(request.state, "user"):
216
+ return RedirectResponse("/login")
217
+ user = request.state.user
218
+ log_id = nanoid.generate()
219
+
220
+ await init_chat_session(user, agent_name, log_id)
221
+ return JSONResponse({ "log_id": log_id })
222
+
125
223
  @router.get("/history/{agent_name}/{log_id}")
126
224
  async def chat_history(request: Request, agent_name: str, log_id: str):
127
225
  user = request.state.user.username
@@ -137,7 +235,8 @@ async def chat_history(request: Request, agent_name: str, log_id: str):
137
235
  return history
138
236
 
139
237
  @router.get("/session/{agent_name}/{log_id}")
140
- async def chat_history(request: Request, agent_name: str, log_id: str):
238
+ async def chat_session(request: Request, agent_name: str, log_id: str, embed: bool = Query(False)):
239
+ # Check authentication (API key or regular user)
141
240
  plugins = list_enabled()
142
241
  if not hasattr(request.state, "user"):
143
242
  return RedirectResponse("/login")
@@ -155,6 +254,10 @@ async def chat_history(request: Request, agent_name: str, log_id: str):
155
254
 
156
255
  if auth_token is not None:
157
256
  chat_data["access_token"] = auth_token
257
+
258
+ # Add embed mode flag
259
+ if embed:
260
+ chat_data["embed_mode"] = True
158
261
 
159
262
  html = await render('chat', chat_data)
160
263
  return HTMLResponse(html)
@@ -241,6 +344,7 @@ async def get_token_count(request: Request, log_id: str):
241
344
 
242
345
  if token_counts is None:
243
346
  return {"status": "error", "message": f"Chat log with ID {log_id} not found"}
347
+
244
348
 
245
349
  return {"status": "ok", "token_counts": token_counts}
246
350
 
@@ -290,9 +394,9 @@ async def delete_chat_session(request: Request, log_id: str, user=Depends(requir
290
394
 
291
395
 
292
396
  @router.get("/chat/{log_id}/tokens")
293
- async def get_token_count(request: Request, log_id: str):
397
+ async def get_token_count_alt(request: Request, log_id: str):
294
398
  """
295
- Get token counts for a chat log identified by log_id, including any delegated tasks.
399
+ Alternative token count endpoint using token_counter module.
296
400
 
297
401
  Parameters:
298
402
  - log_id: The log ID to count tokens for
@@ -306,5 +410,13 @@ async def get_token_count(request: Request, log_id: str):
306
410
 
307
411
  if token_counts is None:
308
412
  return {"status": "error", "message": f"Chat log with ID {log_id} not found"}
413
+
309
414
 
310
415
  return {"status": "ok", "token_counts": token_counts}
416
+
417
+ # Include widget routes
418
+ try:
419
+ from .widget_routes import router as widget_router
420
+ router.include_router(widget_router)
421
+ except ImportError as e:
422
+ print(f"Warning: Could not load widget routes: {e}")
@@ -0,0 +1,20 @@
1
+ # Patch for chat router to add deduplication support
2
+ # This should be integrated into the main router.py file
3
+
4
+ # Add this code to the get_persona_avatar function after line 59:
5
+
6
+ # Check if this is a registry persona with deduplicated assets
7
+ if persona_path.startswith('registry/'):
8
+ persona_json_path = f"personas/{persona_path}/persona.json"
9
+ if os.path.exists(persona_json_path):
10
+ try:
11
+ with open(persona_json_path, 'r') as f:
12
+ persona_data = json.load(f)
13
+
14
+ # Check if persona has asset hashes (deduplicated storage)
15
+ asset_hashes = persona_data.get('asset_hashes', {})
16
+ if 'avatar' in asset_hashes:
17
+ # Redirect to deduplicated asset endpoint
18
+ return RedirectResponse(f"/assets/{asset_hashes['avatar']}")
19
+ except Exception as e:
20
+ print(f"Error checking for deduplicated assets: {e}")
@@ -23,6 +23,36 @@ import base64
23
23
  import nanoid
24
24
  sse_clients = {}
25
25
 
26
+ @service()
27
+ async def prompt(model: str, instructions: str, temperature=0, max_tokens=400, json=False, context=None):
28
+ messages = [
29
+ { "role": "system",
30
+ "content": "Respond to prompt with no extraneous commentary."
31
+ },
32
+ { "role": "user",
33
+ "content": instructions
34
+ }]
35
+
36
+ stream = await context.stream_chat(model, temperature=temperature,
37
+ max_tokens=max_tokens,
38
+ messages=messages,
39
+ json=False,
40
+ context=context)
41
+ text = ""
42
+ if os.environ.get("AH_DEBUG") == "True":
43
+ print("Prompting, instructions ", instructions)
44
+ async for chunk in stream:
45
+ #print("Chunk received: ", chunk)
46
+ if chunk is None or chunk == "":
47
+ continue
48
+ else:
49
+ text += chunk
50
+ if os.environ.get("AH_DEBUG") == "True":
51
+ print(chunk, end='', flush=True)
52
+
53
+ return text
54
+
55
+
26
56
  def results_text(results):
27
57
  text = ""
28
58
  for result in results:
@@ -304,7 +334,7 @@ async def send_message_to_agent(session_id: str, message: str | List[MessagePart
304
334
  actual_results = False
305
335
  await asyncio.sleep(0.001)
306
336
  for result in results:
307
- if result['result'] is not None:
337
+ if 'result' in result and result['result'] is not None:
308
338
  if result['result'] == 'continue':
309
339
  out_results.append(result)
310
340
  continue_processing = True
@@ -0,0 +1,32 @@
1
+ /* Action component full width fix - ONLY target action components */
2
+ action-component {
3
+ display: block !important;
4
+ width: 100% !important;
5
+ }
6
+
7
+ action-component .action-details {
8
+ width: 100% !important;
9
+ display: block !important;
10
+ }
11
+
12
+ action-component .action-details summary {
13
+ width: 100% !important;
14
+ display: block !important;
15
+ box-sizing: border-box !important;
16
+ }
17
+
18
+ /* Action summary styling - brighter text */
19
+ action-component .action-summary {
20
+ background: #333 !important;
21
+ color: #f0f0f0 !important;
22
+ }
23
+
24
+ action-component .param-preview {
25
+ color: #ddd !important;
26
+ }
27
+
28
+ action-component .fn_name {
29
+ color: #f0f0f0 !important;
30
+ }
31
+
32
+ /* DO NOT TOUCH CHAT MESSAGE ALIGNMENT - Let default.css handle it */
@@ -15,11 +15,12 @@ body {
15
15
  }
16
16
 
17
17
  details {
18
- background: rgb(10, 10, 25);
18
+ background: #fff;
19
19
  border: 1px solid rgba(255, 255, 255, 0.1);
20
20
  border-radius: 8px;
21
21
  margin-bottom: 20px;
22
22
  overflow: hidden;
23
+ width: 100%;
23
24
  transition: all 0.3s ease;
24
25
  }
25
26
 
@@ -29,7 +30,7 @@ details[open] {
29
30
 
30
31
  summary {
31
32
  padding: 15px 20px;
32
- background: rgb(15, 15, 30);
33
+ background: #222;
33
34
  color: #f0f0f0;
34
35
  cursor: pointer;
35
36
  transition: background 0.3s ease;
@@ -42,7 +43,8 @@ summary:hover {
42
43
  }
43
44
 
44
45
  details[open] summary {
45
- background: rgb(25, 25, 50);
46
+ /* background: rgb(25, 25, 50); */
47
+ background: #222;
46
48
  }
47
49
 
48
50
  .details-content {
@@ -3,7 +3,7 @@ html, body {
3
3
  color: #f0f0f0;
4
4
  padding: 5px 5px;
5
5
  font-family: ui-sans-serif, -apple-system, system-ui, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, Helvetica, "Apple Color Emoji", Arial, "Segoe UI Emoji", "Segoe UI Symbol";
6
- /* font-size: 16px; */
6
+ font-size: 18px;
7
7
  display: flex;
8
8
  line-height: 1.5;
9
9
  flex-direction: column;
@@ -89,8 +89,10 @@ chat-form {
89
89
  width: 100%;
90
90
  }
91
91
 
92
+
92
93
  chat-message {
93
- max-width: 69%;
94
+ /* max-width: 69%; */
95
+ width: 100%;
94
96
  padding: 4px 8px;
95
97
  margin: 2px 0;
96
98
  display: block;
@@ -127,6 +129,15 @@ chat-message:first-of-type .outer-msg.without-avatar {
127
129
  background-color: transparent;
128
130
  }
129
131
 
132
+ .outer-msg.user {
133
+ flex-direction: column;
134
+ align-items: flex-end;
135
+ }
136
+
137
+ .message:has(.action-summary) {
138
+ width: 100%;
139
+ }
140
+
130
141
  .user {
131
142
  align-self: flex-end;
132
143
  }
@@ -146,6 +157,7 @@ chat-message:first-of-type .outer-msg.without-avatar {
146
157
  /* background-color: #080808; */
147
158
  border: 1px solid #181818;
148
159
  border-radius: 30px;
160
+ width: 80%;
149
161
  }
150
162
 
151
163
  .msg-ai:first-child {
@@ -745,7 +757,16 @@ button:hover {
745
757
  }
746
758
 
747
759
  .param_name { font-weight: bold; }
748
- .param_value { color: yellow; }
760
+ .param_value { color: #ccc; }
761
+
762
+ summary {
763
+ border-radius: 8px;
764
+ color: white;
765
+ }
766
+
767
+ details {
768
+ width: 100%;
769
+ }
749
770
 
750
771
  .fn_result, .code-result {
751
772
  white-space: normal !important;
@@ -3,7 +3,7 @@ html, body {
3
3
  color: #f0f0f0;
4
4
  padding: 5px 5px;
5
5
  font-family: ui-sans-serif, -apple-system, system-ui, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, Helvetica, "Apple Color Emoji", Arial, "Segoe UI Emoji", "Segoe UI Symbol";
6
- /* font-size: 16px; */
6
+ font-size: 18px;
7
7
  display: flex;
8
8
  line-height: 1.5;
9
9
  flex-direction: column;
@@ -89,8 +89,10 @@ chat-form {
89
89
  width: 100%;
90
90
  }
91
91
 
92
+
92
93
  chat-message {
93
- max-width: 69%;
94
+ /* max-width: 69%; */
95
+ width: 100%;
94
96
  padding: 4px 8px;
95
97
  margin: 2px 0;
96
98
  display: block;
@@ -127,6 +129,15 @@ chat-message:first-of-type .outer-msg.without-avatar {
127
129
  background-color: transparent;
128
130
  }
129
131
 
132
+ .outer-msg.user {
133
+ flex-direction: column;
134
+ align-items: flex-end;
135
+ }
136
+
137
+ .message:has(.action-summary) {
138
+ width: 100%;
139
+ }
140
+
130
141
  .user {
131
142
  align-self: flex-end;
132
143
  }
@@ -146,6 +157,7 @@ chat-message:first-of-type .outer-msg.without-avatar {
146
157
  /* background-color: #080808; */
147
158
  border: 1px solid #181818;
148
159
  border-radius: 30px;
160
+ width: 80%;
149
161
  }
150
162
 
151
163
  .msg-ai:first-child {
@@ -745,7 +757,16 @@ button:hover {
745
757
  }
746
758
 
747
759
  .param_name { font-weight: bold; }
748
- .param_value { color: yellow; }
760
+ .param_value { color: #ccc; }
761
+
762
+ summary {
763
+ border-radius: 8px;
764
+ color: white;
765
+ }
766
+
767
+ details {
768
+ width: 100%;
769
+ }
749
770
 
750
771
  .fn_result, .code-result {
751
772
  white-space: normal !important;
@@ -2,3 +2,4 @@
2
2
  @import url('reset.css');
3
3
  @import url('default.css');
4
4
  @import url('mobile.css');
5
+ @import url('action-fix.css');