Upload folder using huggingface_hub (part 3)
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- .gitattributes +214 -0
- docs/res/usage/webui/project-instructions-filled.png +0 -0
- docs/res/usage/webui/project-picker.png +0 -0
- docs/res/usage/webui/projects-empty.png +0 -0
- docs/res/usage/webui/projects-list-created.png +0 -0
- docs/res/usage/webui/skills-selector-checked.png +0 -0
- docs/res/usage/webui/skills-selector.png +0 -0
- docs/res/usage/webui/unread-dot-chat-list.png +0 -0
- docs/setup/dev-setup.md +3 -190
- docs/setup/installation.md +3 -871
- docs/setup/vps-deployment.md +3 -770
- extensions/AGENTS.md +3 -39
- extensions/python/AGENTS.md +3 -68
- extensions/python/_functions/AGENTS.md +3 -33
- extensions/python/_functions/__main__/init_a0/end/_10_register_watchdogs.py +3 -11
- extensions/python/_functions/agent/Agent/handle_exception/end/_40_handle_intervention_exception.py +3 -21
- extensions/python/_functions/agent/Agent/handle_exception/end/_50_handle_repairable_exception.py +3 -25
- extensions/python/_functions/agent/Agent/handle_exception/end/_90_handle_critical_exception.py +3 -43
- extensions/python/_functions/agent/Agent/hist_add_ai_response/end/_10_log_plain_responses.py +3 -47
- extensions/python/_functions/agent/Agent/hist_add_warning/end/_90_stop_unusable_response_loop.py +3 -56
- extensions/python/_functions/agent/Agent/prepare_prompt/end/_00_restore_settings.py +3 -12
- extensions/python/_functions/agent/Agent/prepare_prompt/start/_99_snapshot_settings.py +3 -11
- extensions/python/_functions/agent/AgentContext/run_task/end/_10_mark_state_dirty.py +3 -14
- extensions/python/agent_init/AGENTS.md +3 -26
- extensions/python/agent_init/_10_initial_message.py +3 -44
- extensions/python/agent_init/_15_load_profile_settings.py +3 -53
- extensions/python/banners/AGENTS.md +3 -28
- extensions/python/banners/_10_unsecured_connection.py +3 -63
- extensions/python/banners/_30_system_resources.py +3 -151
- extensions/python/before_main_llm_call/AGENTS.md +3 -26
- extensions/python/before_main_llm_call/_10_log_for_stream.py +3 -33
- extensions/python/error_format/AGENTS.md +3 -26
- extensions/python/error_format/_10_mask_errors.py +3 -20
- extensions/python/hist_add_before/AGENTS.md +3 -26
- extensions/python/hist_add_before/_10_mask_content.py +3 -35
- extensions/python/hist_add_tool_result/AGENTS.md +3 -27
- extensions/python/hist_add_tool_result/_90_save_tool_call_file.py +3 -44
- extensions/python/job_loop/AGENTS.md +3 -26
- extensions/python/job_loop/_20_cleanup_expired_api_chats.py +3 -63
- extensions/python/job_loop/_50_trim_cache.py +3 -9
- extensions/python/message_loop_end/AGENTS.md +3 -27
- extensions/python/message_loop_end/_10_organize_history.py +3 -30
- extensions/python/message_loop_end/_90_save_chat.py +3 -15
- extensions/python/message_loop_prompts_after/AGENTS.md +3 -33
- extensions/python/message_loop_prompts_after/_60_include_current_datetime.py +3 -19
- extensions/python/message_loop_prompts_after/_63_recall_relevant_skills.py +3 -45
- extensions/python/message_loop_prompts_after/_65_include_loaded_skills.py +3 -78
- extensions/python/message_loop_prompts_after/_70_include_agent_info.py +3 -27
- extensions/python/message_loop_prompts_after/_72_include_parallel_jobs.py +3 -13
- extensions/python/message_loop_prompts_after/_75_include_workdir_extras.py +3 -96
.gitattributes
CHANGED
|
@@ -234,3 +234,217 @@ docs/res/usage/webui/model-presets-add.png filter=lfs diff=lfs merge=lfs -text
|
|
| 234 |
docs/res/usage/webui/model-presets-editor.png filter=lfs diff=lfs merge=lfs -text
|
| 235 |
docs/res/usage/webui/project-active-chat.png filter=lfs diff=lfs merge=lfs -text
|
| 236 |
docs/res/usage/webui/project-create-filled.png filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 234 |
docs/res/usage/webui/model-presets-editor.png filter=lfs diff=lfs merge=lfs -text
|
| 235 |
docs/res/usage/webui/project-active-chat.png filter=lfs diff=lfs merge=lfs -text
|
| 236 |
docs/res/usage/webui/project-create-filled.png filter=lfs diff=lfs merge=lfs -text
|
| 237 |
+
docs/res/usage/webui/project-instructions-filled.png filter=lfs diff=lfs merge=lfs -text
|
| 238 |
+
docs/res/usage/webui/project-picker.png filter=lfs diff=lfs merge=lfs -text
|
| 239 |
+
docs/res/usage/webui/projects-empty.png filter=lfs diff=lfs merge=lfs -text
|
| 240 |
+
docs/res/usage/webui/projects-list-created.png filter=lfs diff=lfs merge=lfs -text
|
| 241 |
+
docs/res/usage/webui/skills-selector-checked.png filter=lfs diff=lfs merge=lfs -text
|
| 242 |
+
docs/res/usage/webui/skills-selector.png filter=lfs diff=lfs merge=lfs -text
|
| 243 |
+
docs/res/usage/webui/unread-dot-chat-list.png filter=lfs diff=lfs merge=lfs -text
|
| 244 |
+
docs/setup/dev-setup.md filter=lfs diff=lfs merge=lfs -text
|
| 245 |
+
docs/setup/installation.md filter=lfs diff=lfs merge=lfs -text
|
| 246 |
+
docs/setup/vps-deployment.md filter=lfs diff=lfs merge=lfs -text
|
| 247 |
+
extensions/AGENTS.md filter=lfs diff=lfs merge=lfs -text
|
| 248 |
+
extensions/python/AGENTS.md filter=lfs diff=lfs merge=lfs -text
|
| 249 |
+
extensions/python/_functions/AGENTS.md filter=lfs diff=lfs merge=lfs -text
|
| 250 |
+
extensions/python/_functions/__main__/init_a0/end/_10_register_watchdogs.py filter=lfs diff=lfs merge=lfs -text
|
| 251 |
+
extensions/python/_functions/agent/Agent/handle_exception/end/_40_handle_intervention_exception.py filter=lfs diff=lfs merge=lfs -text
|
| 252 |
+
extensions/python/_functions/agent/Agent/handle_exception/end/_50_handle_repairable_exception.py filter=lfs diff=lfs merge=lfs -text
|
| 253 |
+
extensions/python/_functions/agent/Agent/handle_exception/end/_90_handle_critical_exception.py filter=lfs diff=lfs merge=lfs -text
|
| 254 |
+
extensions/python/_functions/agent/Agent/hist_add_ai_response/end/_10_log_plain_responses.py filter=lfs diff=lfs merge=lfs -text
|
| 255 |
+
extensions/python/_functions/agent/Agent/hist_add_warning/end/_90_stop_unusable_response_loop.py filter=lfs diff=lfs merge=lfs -text
|
| 256 |
+
extensions/python/_functions/agent/Agent/prepare_prompt/end/_00_restore_settings.py filter=lfs diff=lfs merge=lfs -text
|
| 257 |
+
extensions/python/_functions/agent/Agent/prepare_prompt/start/_99_snapshot_settings.py filter=lfs diff=lfs merge=lfs -text
|
| 258 |
+
extensions/python/_functions/agent/AgentContext/run_task/end/_10_mark_state_dirty.py filter=lfs diff=lfs merge=lfs -text
|
| 259 |
+
extensions/python/agent_init/AGENTS.md filter=lfs diff=lfs merge=lfs -text
|
| 260 |
+
extensions/python/agent_init/_10_initial_message.py filter=lfs diff=lfs merge=lfs -text
|
| 261 |
+
extensions/python/agent_init/_15_load_profile_settings.py filter=lfs diff=lfs merge=lfs -text
|
| 262 |
+
extensions/python/banners/AGENTS.md filter=lfs diff=lfs merge=lfs -text
|
| 263 |
+
extensions/python/banners/_10_unsecured_connection.py filter=lfs diff=lfs merge=lfs -text
|
| 264 |
+
extensions/python/banners/_30_system_resources.py filter=lfs diff=lfs merge=lfs -text
|
| 265 |
+
extensions/python/before_main_llm_call/AGENTS.md filter=lfs diff=lfs merge=lfs -text
|
| 266 |
+
extensions/python/before_main_llm_call/_10_log_for_stream.py filter=lfs diff=lfs merge=lfs -text
|
| 267 |
+
extensions/python/error_format/AGENTS.md filter=lfs diff=lfs merge=lfs -text
|
| 268 |
+
extensions/python/error_format/_10_mask_errors.py filter=lfs diff=lfs merge=lfs -text
|
| 269 |
+
extensions/python/hist_add_before/AGENTS.md filter=lfs diff=lfs merge=lfs -text
|
| 270 |
+
extensions/python/hist_add_before/_10_mask_content.py filter=lfs diff=lfs merge=lfs -text
|
| 271 |
+
extensions/python/hist_add_tool_result/AGENTS.md filter=lfs diff=lfs merge=lfs -text
|
| 272 |
+
extensions/python/hist_add_tool_result/_90_save_tool_call_file.py filter=lfs diff=lfs merge=lfs -text
|
| 273 |
+
extensions/python/job_loop/AGENTS.md filter=lfs diff=lfs merge=lfs -text
|
| 274 |
+
extensions/python/job_loop/_20_cleanup_expired_api_chats.py filter=lfs diff=lfs merge=lfs -text
|
| 275 |
+
extensions/python/job_loop/_50_trim_cache.py filter=lfs diff=lfs merge=lfs -text
|
| 276 |
+
extensions/python/message_loop_end/AGENTS.md filter=lfs diff=lfs merge=lfs -text
|
| 277 |
+
extensions/python/message_loop_end/_10_organize_history.py filter=lfs diff=lfs merge=lfs -text
|
| 278 |
+
extensions/python/message_loop_end/_90_save_chat.py filter=lfs diff=lfs merge=lfs -text
|
| 279 |
+
extensions/python/message_loop_prompts_after/AGENTS.md filter=lfs diff=lfs merge=lfs -text
|
| 280 |
+
extensions/python/message_loop_prompts_after/_60_include_current_datetime.py filter=lfs diff=lfs merge=lfs -text
|
| 281 |
+
extensions/python/message_loop_prompts_after/_63_recall_relevant_skills.py filter=lfs diff=lfs merge=lfs -text
|
| 282 |
+
extensions/python/message_loop_prompts_after/_65_include_loaded_skills.py filter=lfs diff=lfs merge=lfs -text
|
| 283 |
+
extensions/python/message_loop_prompts_after/_70_include_agent_info.py filter=lfs diff=lfs merge=lfs -text
|
| 284 |
+
extensions/python/message_loop_prompts_after/_72_include_parallel_jobs.py filter=lfs diff=lfs merge=lfs -text
|
| 285 |
+
extensions/python/message_loop_prompts_after/_75_include_workdir_extras.py filter=lfs diff=lfs merge=lfs -text
|
| 286 |
+
extensions/python/message_loop_prompts_before/AGENTS.md filter=lfs diff=lfs merge=lfs -text
|
| 287 |
+
extensions/python/message_loop_prompts_before/_90_organize_history_wait.py filter=lfs diff=lfs merge=lfs -text
|
| 288 |
+
extensions/python/message_loop_result/AGENTS.md filter=lfs diff=lfs merge=lfs -text
|
| 289 |
+
extensions/python/message_loop_result/_20_empty_response.py filter=lfs diff=lfs merge=lfs -text
|
| 290 |
+
extensions/python/message_loop_result/_30_repeat_response.py filter=lfs diff=lfs merge=lfs -text
|
| 291 |
+
extensions/python/message_loop_start/AGENTS.md filter=lfs diff=lfs merge=lfs -text
|
| 292 |
+
extensions/python/message_loop_start/_10_iteration_no.py filter=lfs diff=lfs merge=lfs -text
|
| 293 |
+
extensions/python/monologue_end/AGENTS.md filter=lfs diff=lfs merge=lfs -text
|
| 294 |
+
extensions/python/monologue_end/_90_waiting_for_input_msg.py filter=lfs diff=lfs merge=lfs -text
|
| 295 |
+
extensions/python/monologue_start/AGENTS.md filter=lfs diff=lfs merge=lfs -text
|
| 296 |
+
extensions/python/process_chain_end/AGENTS.md filter=lfs diff=lfs merge=lfs -text
|
| 297 |
+
extensions/python/process_chain_end/_50_process_queue.py filter=lfs diff=lfs merge=lfs -text
|
| 298 |
+
extensions/python/reasoning_stream/AGENTS.md filter=lfs diff=lfs merge=lfs -text
|
| 299 |
+
extensions/python/reasoning_stream/_10_log_from_stream.py filter=lfs diff=lfs merge=lfs -text
|
| 300 |
+
extensions/python/reasoning_stream_chunk/AGENTS.md filter=lfs diff=lfs merge=lfs -text
|
| 301 |
+
extensions/python/reasoning_stream_chunk/_10_mask_stream.py filter=lfs diff=lfs merge=lfs -text
|
| 302 |
+
extensions/python/reasoning_stream_end/AGENTS.md filter=lfs diff=lfs merge=lfs -text
|
| 303 |
+
extensions/python/reasoning_stream_end/_10_mask_end.py filter=lfs diff=lfs merge=lfs -text
|
| 304 |
+
extensions/python/response_stream/AGENTS.md filter=lfs diff=lfs merge=lfs -text
|
| 305 |
+
extensions/python/response_stream/_10_log_from_stream.py filter=lfs diff=lfs merge=lfs -text
|
| 306 |
+
extensions/python/response_stream/_15_replace_include_alias.py filter=lfs diff=lfs merge=lfs -text
|
| 307 |
+
extensions/python/response_stream/_20_live_response.py filter=lfs diff=lfs merge=lfs -text
|
| 308 |
+
extensions/python/response_stream_chunk/AGENTS.md filter=lfs diff=lfs merge=lfs -text
|
| 309 |
+
extensions/python/response_stream_chunk/_10_mask_stream.py filter=lfs diff=lfs merge=lfs -text
|
| 310 |
+
extensions/python/response_stream_end/AGENTS.md filter=lfs diff=lfs merge=lfs -text
|
| 311 |
+
extensions/python/response_stream_end/_10_mask_end.py filter=lfs diff=lfs merge=lfs -text
|
| 312 |
+
extensions/python/response_stream_end/_15_log_from_stream_end.py filter=lfs diff=lfs merge=lfs -text
|
| 313 |
+
extensions/python/startup_migration/AGENTS.md filter=lfs diff=lfs merge=lfs -text
|
| 314 |
+
extensions/python/startup_migration/_10_self_update_manager.py filter=lfs diff=lfs merge=lfs -text
|
| 315 |
+
extensions/python/system_prompt/AGENTS.md filter=lfs diff=lfs merge=lfs -text
|
| 316 |
+
extensions/python/system_prompt/_10_main_prompt.py filter=lfs diff=lfs merge=lfs -text
|
| 317 |
+
extensions/python/system_prompt/_11_tools_prompt.py filter=lfs diff=lfs merge=lfs -text
|
| 318 |
+
extensions/python/system_prompt/_12_mcp_prompt.py filter=lfs diff=lfs merge=lfs -text
|
| 319 |
+
extensions/python/system_prompt/_13_secrets_prompt.py filter=lfs diff=lfs merge=lfs -text
|
| 320 |
+
extensions/python/system_prompt/_13_skills_prompt.py filter=lfs diff=lfs merge=lfs -text
|
| 321 |
+
extensions/python/system_prompt/_14_project_prompt.py filter=lfs diff=lfs merge=lfs -text
|
| 322 |
+
extensions/python/tool_execute_after/AGENTS.md filter=lfs diff=lfs merge=lfs -text
|
| 323 |
+
extensions/python/tool_execute_after/_10_mask_secrets.py filter=lfs diff=lfs merge=lfs -text
|
| 324 |
+
extensions/python/tool_execute_before/AGENTS.md filter=lfs diff=lfs merge=lfs -text
|
| 325 |
+
extensions/python/tool_execute_before/_10_replace_last_tool_output.py filter=lfs diff=lfs merge=lfs -text
|
| 326 |
+
extensions/python/tool_execute_before/_10_unmask_secrets.py filter=lfs diff=lfs merge=lfs -text
|
| 327 |
+
extensions/python/tool_execute_before/_20_block_parallel_recursion.py filter=lfs diff=lfs merge=lfs -text
|
| 328 |
+
extensions/python/user_message_ui/AGENTS.md filter=lfs diff=lfs merge=lfs -text
|
| 329 |
+
extensions/python/user_message_ui/_10_update_check.py filter=lfs diff=lfs merge=lfs -text
|
| 330 |
+
extensions/python/util_model_call_before/AGENTS.md filter=lfs diff=lfs merge=lfs -text
|
| 331 |
+
extensions/python/util_model_call_before/_10_mask_secrets.py filter=lfs diff=lfs merge=lfs -text
|
| 332 |
+
extensions/python/webui_ws_connect/AGENTS.md filter=lfs diff=lfs merge=lfs -text
|
| 333 |
+
extensions/python/webui_ws_connect/_10_state_sync.py filter=lfs diff=lfs merge=lfs -text
|
| 334 |
+
extensions/python/webui_ws_disconnect/AGENTS.md filter=lfs diff=lfs merge=lfs -text
|
| 335 |
+
extensions/python/webui_ws_disconnect/_10_state_sync.py filter=lfs diff=lfs merge=lfs -text
|
| 336 |
+
extensions/python/webui_ws_event/AGENTS.md filter=lfs diff=lfs merge=lfs -text
|
| 337 |
+
extensions/python/webui_ws_event/_10_state_sync.py filter=lfs diff=lfs merge=lfs -text
|
| 338 |
+
extensions/webui/AGENTS.md filter=lfs diff=lfs merge=lfs -text
|
| 339 |
+
extensions/webui/fetch_api_call_after/AGENTS.md filter=lfs diff=lfs merge=lfs -text
|
| 340 |
+
extensions/webui/fetch_api_call_before/AGENTS.md filter=lfs diff=lfs merge=lfs -text
|
| 341 |
+
extensions/webui/get_message_handler/AGENTS.md filter=lfs diff=lfs merge=lfs -text
|
| 342 |
+
extensions/webui/initFw_end/AGENTS.md filter=lfs diff=lfs merge=lfs -text
|
| 343 |
+
extensions/webui/initFw_end/restoreRestorableModals.js filter=lfs diff=lfs merge=lfs -text
|
| 344 |
+
extensions/webui/initFw_end/selfUpdateGlobal.js filter=lfs diff=lfs merge=lfs -text
|
| 345 |
+
extensions/webui/json_api_call_after/AGENTS.md filter=lfs diff=lfs merge=lfs -text
|
| 346 |
+
extensions/webui/json_api_call_after/cache_reset.js filter=lfs diff=lfs merge=lfs -text
|
| 347 |
+
extensions/webui/json_api_call_before/AGENTS.md filter=lfs diff=lfs merge=lfs -text
|
| 348 |
+
extensions/webui/right-canvas-panels/AGENTS.md filter=lfs diff=lfs merge=lfs -text
|
| 349 |
+
extensions/webui/right-canvas-panels/files-panel.html filter=lfs diff=lfs merge=lfs -text
|
| 350 |
+
extensions/webui/right_canvas_register_surfaces/AGENTS.md filter=lfs diff=lfs merge=lfs -text
|
| 351 |
+
extensions/webui/right_canvas_register_surfaces/register-files.js filter=lfs diff=lfs merge=lfs -text
|
| 352 |
+
extensions/webui/right_canvas_register_surfaces/register-remote-link.js filter=lfs diff=lfs merge=lfs -text
|
| 353 |
+
extensions/webui/right_canvas_register_surfaces/register-space-agent.js filter=lfs diff=lfs merge=lfs -text
|
| 354 |
+
extensions/webui/set_messages_after_loop/AGENTS.md filter=lfs diff=lfs merge=lfs -text
|
| 355 |
+
extensions/webui/set_messages_before_loop/AGENTS.md filter=lfs diff=lfs merge=lfs -text
|
| 356 |
+
extensions/webui/webui_ws_push/AGENTS.md filter=lfs diff=lfs merge=lfs -text
|
| 357 |
+
extensions/webui/webui_ws_push/clear_cache.js filter=lfs diff=lfs merge=lfs -text
|
| 358 |
+
helpers/AGENTS.md filter=lfs diff=lfs merge=lfs -text
|
| 359 |
+
helpers/api.py filter=lfs diff=lfs merge=lfs -text
|
| 360 |
+
helpers/api.py.dox.md filter=lfs diff=lfs merge=lfs -text
|
| 361 |
+
helpers/attachment_manager.py filter=lfs diff=lfs merge=lfs -text
|
| 362 |
+
helpers/attachment_manager.py.dox.md filter=lfs diff=lfs merge=lfs -text
|
| 363 |
+
helpers/backup.py filter=lfs diff=lfs merge=lfs -text
|
| 364 |
+
helpers/backup.py.dox.md filter=lfs diff=lfs merge=lfs -text
|
| 365 |
+
helpers/browser.py filter=lfs diff=lfs merge=lfs -text
|
| 366 |
+
helpers/browser.py.dox.md filter=lfs diff=lfs merge=lfs -text
|
| 367 |
+
helpers/cache.py filter=lfs diff=lfs merge=lfs -text
|
| 368 |
+
helpers/cache.py.dox.md filter=lfs diff=lfs merge=lfs -text
|
| 369 |
+
helpers/call_llm.py filter=lfs diff=lfs merge=lfs -text
|
| 370 |
+
helpers/call_llm.py.dox.md filter=lfs diff=lfs merge=lfs -text
|
| 371 |
+
helpers/chat_media.py filter=lfs diff=lfs merge=lfs -text
|
| 372 |
+
helpers/chat_media.py.dox.md filter=lfs diff=lfs merge=lfs -text
|
| 373 |
+
helpers/cli_tunnel.py filter=lfs diff=lfs merge=lfs -text
|
| 374 |
+
helpers/cli_tunnel.py.dox.md filter=lfs diff=lfs merge=lfs -text
|
| 375 |
+
helpers/cloudflare_tunnel._py filter=lfs diff=lfs merge=lfs -text
|
| 376 |
+
helpers/cloudflare_tunnel.py filter=lfs diff=lfs merge=lfs -text
|
| 377 |
+
helpers/cloudflare_tunnel.py.dox.md filter=lfs diff=lfs merge=lfs -text
|
| 378 |
+
helpers/context.py filter=lfs diff=lfs merge=lfs -text
|
| 379 |
+
helpers/context.py.dox.md filter=lfs diff=lfs merge=lfs -text
|
| 380 |
+
helpers/context_utils.py filter=lfs diff=lfs merge=lfs -text
|
| 381 |
+
helpers/context_utils.py.dox.md filter=lfs diff=lfs merge=lfs -text
|
| 382 |
+
helpers/crypto.py filter=lfs diff=lfs merge=lfs -text
|
| 383 |
+
helpers/crypto.py.dox.md filter=lfs diff=lfs merge=lfs -text
|
| 384 |
+
helpers/defer.py filter=lfs diff=lfs merge=lfs -text
|
| 385 |
+
helpers/defer.py.dox.md filter=lfs diff=lfs merge=lfs -text
|
| 386 |
+
helpers/dirty_json.py filter=lfs diff=lfs merge=lfs -text
|
| 387 |
+
helpers/dirty_json.py.dox.md filter=lfs diff=lfs merge=lfs -text
|
| 388 |
+
helpers/docker.py filter=lfs diff=lfs merge=lfs -text
|
| 389 |
+
helpers/docker.py.dox.md filter=lfs diff=lfs merge=lfs -text
|
| 390 |
+
helpers/document_query.py filter=lfs diff=lfs merge=lfs -text
|
| 391 |
+
helpers/document_query.py.dox.md filter=lfs diff=lfs merge=lfs -text
|
| 392 |
+
helpers/dotenv.py filter=lfs diff=lfs merge=lfs -text
|
| 393 |
+
helpers/dotenv.py.dox.md filter=lfs diff=lfs merge=lfs -text
|
| 394 |
+
helpers/duckduckgo_search.py filter=lfs diff=lfs merge=lfs -text
|
| 395 |
+
helpers/duckduckgo_search.py.dox.md filter=lfs diff=lfs merge=lfs -text
|
| 396 |
+
helpers/email_client.py filter=lfs diff=lfs merge=lfs -text
|
| 397 |
+
helpers/email_client.py.dox.md filter=lfs diff=lfs merge=lfs -text
|
| 398 |
+
helpers/ephemeral_images.py filter=lfs diff=lfs merge=lfs -text
|
| 399 |
+
helpers/ephemeral_images.py.dox.md filter=lfs diff=lfs merge=lfs -text
|
| 400 |
+
helpers/errors.py filter=lfs diff=lfs merge=lfs -text
|
| 401 |
+
helpers/errors.py.dox.md filter=lfs diff=lfs merge=lfs -text
|
| 402 |
+
helpers/extension.py filter=lfs diff=lfs merge=lfs -text
|
| 403 |
+
helpers/extension.py.dox.md filter=lfs diff=lfs merge=lfs -text
|
| 404 |
+
helpers/extract_tools.py filter=lfs diff=lfs merge=lfs -text
|
| 405 |
+
helpers/extract_tools.py.dox.md filter=lfs diff=lfs merge=lfs -text
|
| 406 |
+
helpers/faiss_monkey_patch.py filter=lfs diff=lfs merge=lfs -text
|
| 407 |
+
helpers/faiss_monkey_patch.py.dox.md filter=lfs diff=lfs merge=lfs -text
|
| 408 |
+
helpers/fasta2a_client.py filter=lfs diff=lfs merge=lfs -text
|
| 409 |
+
helpers/fasta2a_client.py.dox.md filter=lfs diff=lfs merge=lfs -text
|
| 410 |
+
helpers/fasta2a_server.py filter=lfs diff=lfs merge=lfs -text
|
| 411 |
+
helpers/fasta2a_server.py.dox.md filter=lfs diff=lfs merge=lfs -text
|
| 412 |
+
helpers/file_browser.py filter=lfs diff=lfs merge=lfs -text
|
| 413 |
+
helpers/file_browser.py.dox.md filter=lfs diff=lfs merge=lfs -text
|
| 414 |
+
helpers/file_tree.py filter=lfs diff=lfs merge=lfs -text
|
| 415 |
+
helpers/file_tree.py.dox.md filter=lfs diff=lfs merge=lfs -text
|
| 416 |
+
helpers/files.py filter=lfs diff=lfs merge=lfs -text
|
| 417 |
+
helpers/files.py.dox.md filter=lfs diff=lfs merge=lfs -text
|
| 418 |
+
helpers/functions.py filter=lfs diff=lfs merge=lfs -text
|
| 419 |
+
helpers/functions.py.dox.md filter=lfs diff=lfs merge=lfs -text
|
| 420 |
+
helpers/git.py filter=lfs diff=lfs merge=lfs -text
|
| 421 |
+
helpers/git.py.dox.md filter=lfs diff=lfs merge=lfs -text
|
| 422 |
+
helpers/guids.py filter=lfs diff=lfs merge=lfs -text
|
| 423 |
+
helpers/guids.py.dox.md filter=lfs diff=lfs merge=lfs -text
|
| 424 |
+
helpers/history.py filter=lfs diff=lfs merge=lfs -text
|
| 425 |
+
helpers/history.py.dox.md filter=lfs diff=lfs merge=lfs -text
|
| 426 |
+
helpers/images.py filter=lfs diff=lfs merge=lfs -text
|
| 427 |
+
helpers/images.py.dox.md filter=lfs diff=lfs merge=lfs -text
|
| 428 |
+
helpers/integration_commands.py filter=lfs diff=lfs merge=lfs -text
|
| 429 |
+
helpers/integration_commands.py.dox.md filter=lfs diff=lfs merge=lfs -text
|
| 430 |
+
helpers/job_loop.py filter=lfs diff=lfs merge=lfs -text
|
| 431 |
+
helpers/job_loop.py.dox.md filter=lfs diff=lfs merge=lfs -text
|
| 432 |
+
helpers/kvp.py filter=lfs diff=lfs merge=lfs -text
|
| 433 |
+
helpers/kvp.py.dox.md filter=lfs diff=lfs merge=lfs -text
|
| 434 |
+
helpers/litellm_transport.py filter=lfs diff=lfs merge=lfs -text
|
| 435 |
+
helpers/litellm_transport.py.dox.md filter=lfs diff=lfs merge=lfs -text
|
| 436 |
+
helpers/llm_result.py filter=lfs diff=lfs merge=lfs -text
|
| 437 |
+
helpers/llm_result.py.dox.md filter=lfs diff=lfs merge=lfs -text
|
| 438 |
+
helpers/localization.py filter=lfs diff=lfs merge=lfs -text
|
| 439 |
+
helpers/localization.py.dox.md filter=lfs diff=lfs merge=lfs -text
|
| 440 |
+
helpers/log.py filter=lfs diff=lfs merge=lfs -text
|
| 441 |
+
helpers/log.py.dox.md filter=lfs diff=lfs merge=lfs -text
|
| 442 |
+
helpers/login.py filter=lfs diff=lfs merge=lfs -text
|
| 443 |
+
helpers/login.py.dox.md filter=lfs diff=lfs merge=lfs -text
|
| 444 |
+
helpers/mcp_handler.py filter=lfs diff=lfs merge=lfs -text
|
| 445 |
+
helpers/mcp_handler.py.dox.md filter=lfs diff=lfs merge=lfs -text
|
| 446 |
+
helpers/mcp_server.py filter=lfs diff=lfs merge=lfs -text
|
| 447 |
+
helpers/mcp_server.py.dox.md filter=lfs diff=lfs merge=lfs -text
|
| 448 |
+
helpers/media_artifacts.py filter=lfs diff=lfs merge=lfs -text
|
| 449 |
+
helpers/media_artifacts.py.dox.md filter=lfs diff=lfs merge=lfs -text
|
| 450 |
+
helpers/message_queue.py filter=lfs diff=lfs merge=lfs -text
|
docs/res/usage/webui/project-instructions-filled.png
CHANGED
|
|
Git LFS Details
|
docs/res/usage/webui/project-picker.png
CHANGED
|
|
Git LFS Details
|
docs/res/usage/webui/projects-empty.png
CHANGED
|
|
Git LFS Details
|
docs/res/usage/webui/projects-list-created.png
CHANGED
|
|
Git LFS Details
|
docs/res/usage/webui/skills-selector-checked.png
CHANGED
|
|
Git LFS Details
|
docs/res/usage/webui/skills-selector.png
CHANGED
|
|
Git LFS Details
|
docs/res/usage/webui/unread-dot-chat-list.png
CHANGED
|
|
Git LFS Details
|
docs/setup/dev-setup.md
CHANGED
|
@@ -1,190 +1,3 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
[](https://www.youtube.com/watch?v=KE39P4qBjDk)
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
> [!WARNING]
|
| 10 |
-
> This guide is for developers and contributors. It assumes you have a basic understanding of how to use Git/GitHub, Docker, IDEs and Python.
|
| 11 |
-
|
| 12 |
-
> [!NOTE]
|
| 13 |
-
> - Agent Zero runs in a Docker container, this simplifies installation and ensures unified environment and behavior across systems.
|
| 14 |
-
> - Developing and debugging in a container would be complicated though, therefore we use a hybrid approach where the python framework runs on your machine (in VS Code for example) and only connects to a Dockerized instance when it needs to execute code or use other pre-installed functionality like the built-in search engine.
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
## To follow this guide you will need:
|
| 18 |
-
1. VS Code compatible IDE (VS Code, Cursor, Windsurf...)
|
| 19 |
-
2. Python environment (Conda, venv, uv...)
|
| 20 |
-
3. Docker (Docker Desktop, docker-ce...)
|
| 21 |
-
4. (optional) Git/GitHub
|
| 22 |
-
|
| 23 |
-
> [!NOTE]
|
| 24 |
-
> I will be using clean VS Code, Conda and Docker Desktop in this example on MacOS.
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
## Step 0: Install required software
|
| 28 |
-
- See the list above and install the software required if you don't already have it.
|
| 29 |
-
- You can choose your own variants, but Python, Docker and a VS Code compatible IDE are required.
|
| 30 |
-
- For Python you can choose your environment manager - base Python venv, Conda, uv...
|
| 31 |
-
|
| 32 |
-
## Step 1: Clone or download the repository
|
| 33 |
-
- Agent Zero is available on GitHub [github.com/agent0ai/agent-zero](https://github.com/agent0ai/agent-zero).
|
| 34 |
-
- You can download the files using a browser and extract or run `git clone https://github.com/agent0ai/agent-zero` in your desired directory.
|
| 35 |
-
|
| 36 |
-
> [!NOTE]
|
| 37 |
-
> In my case, I used `cd ~/Desktop` and `git clone https://github.com/agent0ai/agent-zero`, so my project folder is `~/Desktop/agent-zero`.
|
| 38 |
-
|
| 39 |
-
## Step 2: Open project folder in your IDE
|
| 40 |
-
- I will be using plain and clean VS Code for this example to make sure I don't skip any setup part, you can use any of it's variants like Cursor, Windsurf etc.
|
| 41 |
-
- Agent Zero comes with `.vscode` folder that contains basic setup, recommended extensions, and debugger profiles. These will help us a lot.
|
| 42 |
-
|
| 43 |
-
1. Open your IDE and open the project folder using `File > Open Folder` and select your folder, in my case `~/Desktop/agent-zero`.
|
| 44 |
-
2. You will probably be prompted to trust the directory, confirm that.
|
| 45 |
-
3. You should now have the project open in your IDE
|
| 46 |
-

|
| 47 |
-
|
| 48 |
-
# Step 3: Prepare your IDE:
|
| 49 |
-
1. Notice the prompt in lower right corner of the screenshot above to install recommended extensions, this comes from the `.vscode/extensions.json` file. It contains Python language support, debugger and error helper, install them by confirming the popup or manually in Extensions tab of your IDE. These are the extensions mentioned:
|
| 50 |
-
```
|
| 51 |
-
usernamehw.errorlens
|
| 52 |
-
ms-python.debugpy
|
| 53 |
-
ms-python.python
|
| 54 |
-
```
|
| 55 |
-
|
| 56 |
-
Now when you select one of the python files in the project, you should see proper Python syntax highlighting and error detection. It should immediately show some errors, because we did not yet install dependencies.
|
| 57 |
-

|
| 58 |
-
|
| 59 |
-
2. Prepare the python environment to run Agent Zero in. This step assumes you have some Python runtime installed. By clicking the python version in lower right corner (3.13.1 in my example), you should get a list of available environments. You can click the `+ Create Virtual Environment` button. You might be prompted to select the environment manager if you have multiple installed. I have venv and Conda, I will select Conda here. I'm also prompted for desired python version, I will select 3.12, that is known to work well.
|
| 60 |
-

|
| 61 |
-

|
| 62 |
-
|
| 63 |
-
- Your new environment should be automatically activated. If not, select it in the lower right corner. You might need to open a new terminal in VS Code to reflect the changes with `Terminal > New Terminal` or clicking the `+` button in the terminal tab. Your terminal prompt should now start with your environment name/path, in my case `(/Users/frdel/Desktop/agent-zero/.conda)` This shows the environment is active in the terminal.
|
| 64 |
-
|
| 65 |
-

|
| 66 |
-
|
| 67 |
-
3. Install dependencies. Run these commands from the project root:
|
| 68 |
-
|
| 69 |
-
```bash
|
| 70 |
-
pip install -r requirements.txt
|
| 71 |
-
PLAYWRIGHT_BROWSERS_PATH=./tmp/playwright patchright install chromium --no-shell
|
| 72 |
-
```
|
| 73 |
-
|
| 74 |
-
The first command installs Python dependencies.
|
| 75 |
-
|
| 76 |
-
The second command installs full Patchright Chromium into `./tmp/playwright`,
|
| 77 |
-
relative to the project root. Docker images use the absolute path
|
| 78 |
-
`/a0/tmp/playwright` and ship Chromium preinstalled.
|
| 79 |
-
|
| 80 |
-
If you skip the second command, local development can still download Chromium on
|
| 81 |
-
first Browser use through `ensure_playwright_binary()` in
|
| 82 |
-
`plugins/_browser/helpers/playwright.py`. Pre-installing avoids that wait.
|
| 83 |
-
|
| 84 |
-
See the [Browser Guide](../guides/browser.md) for the Browser surface,
|
| 85 |
-
screenshots, annotations, and host-browser mode.
|
| 86 |
-
Errors in the code editor caused by missing packages should now be gone. If not, try reloading the window.
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
## Step 4: Run Agent Zero in the IDE
|
| 90 |
-
Great work! Now you should be able to run Agent Zero from your IDE including real-time debugging.
|
| 91 |
-
It will not be able to do code execution and few other features requiring the Docker container just yet, but most of the framework will already work.
|
| 92 |
-
|
| 93 |
-
1. The project is pre-configured for debugging. Go to Debugging tab, select "run_ui.py" and click the green play button (or press F5 by default). The configuration can be found at `.vscode/launch.json`.
|
| 94 |
-
|
| 95 |
-

|
| 96 |
-
|
| 97 |
-
The framework will run at the default port 5000. If you open `http://localhost:5000` in your browser and see `ERR_EMPTY_RESPONSE`, don't panic, you may need to select another port like I did for some reason. If you need to change the default port, you can add `"--port=5555"` to the args in the `.vscode/launch.json` file or you can create a `.env` file in the root directory and set the `WEB_UI_PORT` variable to the desired port.
|
| 98 |
-
|
| 99 |
-
You can also set the bind host via `"--host=0.0.0.0"` (or `WEB_UI_HOST=0.0.0.0`).
|
| 100 |
-
|
| 101 |
-
It may take a while the first time. You should see output like the screenshot below. The RFC error is ok for now as we did not yet connect our local development to another instance in docker.
|
| 102 |
-

|
| 103 |
-
|
| 104 |
-
|
| 105 |
-
After inserting my API key in settings, my Agent Zero instance works. I can send a simple message and get a response.
|
| 106 |
-
Some tools like code execution will not work yet because they need to be connected to a Dockerized instance.
|
| 107 |
-
|
| 108 |
-

|
| 109 |
-
|
| 110 |
-
|
| 111 |
-
## Debugging
|
| 112 |
-
- You can try out the debugger already by placing a breakpoint somewhere in the python code.
|
| 113 |
-
- Let's open `python/api/message.py` for example and place a breakpoint at the beginning of the `communicate` function by clicking on the left of the row number. A red dot should appear showing a breakpoint is set.
|
| 114 |
-
|
| 115 |
-

|
| 116 |
-
|
| 117 |
-
- Now when I send a message in the UI, the debugger will pause the execution at the breakpoint and allow me to inspect all the runtime variables and run the code step by step, even modify the variables or jump to another locations in the code. No more print statements needed!
|
| 118 |
-
|
| 119 |
-

|
| 120 |
-
|
| 121 |
-
|
| 122 |
-
## Step 5: Run another instance of Agent Zero in Docker
|
| 123 |
-
- Some parts of A0 require standardized linux environment, additional web services and preinstalled binaries that would be unneccessarily complex to set up in a local environment.
|
| 124 |
-
- To make development easier, we can use existing A0 instance in docker and forward some requests to be executed there using SSH and RFC (Remote Function Call).
|
| 125 |
-
|
| 126 |
-
1. Pull the docker image `agent0ai/agent-zero` from Docker Hub and run it with a web port (`80`) mapped and SSH port (`22`) mapped.
|
| 127 |
-
If you want, you can also map the `/a0` folder to our local project folder as well, this way we can update our local instance and the docker instance at the same time.
|
| 128 |
-
This is how it looks in my example: port `80` is mapped to `8880` on the host and `22` to `8822`, `/a0` folder mapped to `/Users/frdel/Desktop/agent-zero`:
|
| 129 |
-
|
| 130 |
-

|
| 131 |
-

|
| 132 |
-
|
| 133 |
-
|
| 134 |
-
## Step 6: Configure SSH and RFC connection
|
| 135 |
-
- The last step is to configure the local development (VS Code) instance and the dockerized instance to communicate with each other. This is very simple and can be done in the settings in the Web UI of both instances.
|
| 136 |
-
- In my example the dark themed instance is the VS Code one, the light themed one is the dockerized instance.
|
| 137 |
-
|
| 138 |
-
1. Open the "Settings" page in the Web UI of your dockerized instance and go in the "Development" section.
|
| 139 |
-
2. Set the `RFC Password` field to a new password and save.
|
| 140 |
-
3. Open the "Settings" page in the Web UI of your local instance and go in the "Development" section.
|
| 141 |
-
4. Here set the `RFC Password` field to the same password you used in the dockerized instance. Also set the SSH port and HTTP port the same numbers you used when creating the container - in my case `8822` for SSH and `8880` for HTTP. The `RFC Destination URL` will most probably stay `localhost` as both instances are running on the host machine.
|
| 142 |
-
5. Click save and test by asking your agent to do something in the terminal, like "Get current OS version". It should be able to communicate with the dockerized instance via RFC and SSH and execute the command there, responding with something like "Kali GNU/Linux Rolling".
|
| 143 |
-
|
| 144 |
-
My Dockerized instance:
|
| 145 |
-

|
| 146 |
-
|
| 147 |
-
My VS Code instance:
|
| 148 |
-

|
| 149 |
-
|
| 150 |
-
## RFC Notes (Host IDE + Docker Execution)
|
| 151 |
-
Agent Zero runs code inside the container by default. If you are running the framework locally in your IDE but want tools (like code execution) to run in Docker, configure RFC in **Settings -> Development** and point it to a running Agent Zero container. This routes execution through SSH/RFC to the container while keeping the UI and agent loop on your host.
|
| 152 |
-
|
| 153 |
-
|
| 154 |
-
# Congratulations!
|
| 155 |
-
|
| 156 |
-
You have successfully set up a complete Agent Zero development environment! You now have:
|
| 157 |
-
|
| 158 |
-
- A local development instance running in your IDE with full debugging capabilities
|
| 159 |
-
- A dockerized instance for code execution and system operations
|
| 160 |
-
- RFC and SSH communication between both instances
|
| 161 |
-
- The ability to develop, debug, and test Agent Zero features seamlessly
|
| 162 |
-
|
| 163 |
-
You're now ready to contribute to Agent Zero, create custom extensions, or modify the framework to suit your needs. Happy coding!
|
| 164 |
-
|
| 165 |
-
|
| 166 |
-
## Next steps
|
| 167 |
-
- See [Create a Small Plugin](../guides/create-plugin.md) before building a new plugin.
|
| 168 |
-
- Use [DeepWiki for Agent Zero](https://deepwiki.com/agent0ai/agent-zero) for architecture and source-linked internals.
|
| 169 |
-
- See [Contributing to Agent Zero](../guides/contribution.md) for contribution basics.
|
| 170 |
-
|
| 171 |
-
## Configuration via Environment Variables
|
| 172 |
-
|
| 173 |
-
For development and testing, you can override default settings using the `.env` file with `A0_SET_` prefixed variables:
|
| 174 |
-
|
| 175 |
-
```env
|
| 176 |
-
# Add to your .env file
|
| 177 |
-
A0_SET_chat_model_provider=ollama
|
| 178 |
-
A0_SET_chat_model_name=llama3.2
|
| 179 |
-
A0_SET_chat_model_api_base=http://localhost:11434
|
| 180 |
-
A0_SET_memory_recall_interval=5
|
| 181 |
-
```
|
| 182 |
-
|
| 183 |
-
These environment variables automatically override the hardcoded defaults in `get_default_settings()` without modifying code. Useful for testing different configurations or multi-environment setups.
|
| 184 |
-
|
| 185 |
-
## Want to build your docker image?
|
| 186 |
-
- You can use the `DockerfileLocal` to build your docker image.
|
| 187 |
-
- Navigate to your project root in the terminal and run `docker build -f DockerfileLocal -t agent-zero-local --build-arg CACHE_DATE=$(date +%Y-%m-%d:%H:%M:%S) .`
|
| 188 |
-
- The `CACHE_DATE` argument is optional, it is used to cache most of the build process and only rebuild the last steps when the files or dependencies change.
|
| 189 |
-
- See `docker/run/build.txt` for more build command examples.
|
| 190 |
-
- Automated Docker Hub publishing for release tags is handled by `.github/workflows/docker-publish.yml`. The latest eligible `main` tag generates its GitHub release body on the fly from commit subjects and descriptions via OpenRouter.
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:71d5be20f1035b01e37236efe2d1baedaf829baf99e575cf841b9db2d47f96b6
|
| 3 |
+
size 12391
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
docs/setup/installation.md
CHANGED
|
@@ -1,871 +1,3 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
---
|
| 6 |
-
|
| 7 |
-
## Quick Start (Recommended)
|
| 8 |
-
|
| 9 |
-
Agent Zero runs as a Docker container, and you now have two friendly ways to get
|
| 10 |
-
there:
|
| 11 |
-
|
| 12 |
-
- **A0 Launcher** is the desktop app. It can download Agent Zero, create and
|
| 13 |
-
manage Instances, and help set up the local container runtime when needed.
|
| 14 |
-
- **A0 Install** is the terminal installer. It is best for SSH sessions,
|
| 15 |
-
servers, scripted setup, recovery shells, or users who prefer commands.
|
| 16 |
-
|
| 17 |
-
If Docker is already installed and running, you can also start the container
|
| 18 |
-
directly.
|
| 19 |
-
|
| 20 |
-
### A0 Launcher
|
| 21 |
-
|
| 22 |
-
Use **A0 Launcher** when you want the guided desktop path. Download the app for
|
| 23 |
-
your platform, open it, and let it check Docker or set up a runtime before it
|
| 24 |
-
downloads Agent Zero.
|
| 25 |
-
|
| 26 |
-
#### Downloads
|
| 27 |
-
|
| 28 |
-
| Architecture | macOS | Linux | Windows |
|
| 29 |
-
| --- | --- | --- | --- |
|
| 30 |
-
| x86 | [Mac Intel](https://github.com/agent0ai/a0-launcher/releases/download/v0.9/a0-launcher-0.9-macos-x64.dmg) | [Linux x86](https://github.com/agent0ai/a0-launcher/releases/download/v0.9/a0-launcher-0.9-linux-x64.AppImage) | [Windows x86](https://github.com/agent0ai/a0-launcher/releases/download/v0.9/a0-launcher-0.9-windows-x64.exe) |
|
| 31 |
-
| ARM64 | [Mac Apple Silicon](https://github.com/agent0ai/a0-launcher/releases/download/v0.9/a0-launcher-0.9-macos-arm64.dmg) | [Linux ARM64](https://github.com/agent0ai/a0-launcher/releases/download/v0.9/a0-launcher-0.9-linux-arm64.AppImage) | [Windows ARM64](https://github.com/agent0ai/a0-launcher/releases/download/v0.9/a0-launcher-0.9-windows-arm64.exe) |
|
| 32 |
-
|
| 33 |
-
See the [A0 Launcher v0.9 release](https://github.com/agent0ai/a0-launcher/releases/tag/v0.9)
|
| 34 |
-
for release notes and updater metadata. See the
|
| 35 |
-
[Launcher guide](../guides/launcher.md) for the first-run walkthrough.
|
| 36 |
-
|
| 37 |
-
### A0 Install
|
| 38 |
-
|
| 39 |
-
Use **A0 Install** when you want the command-line path. The installer creates a
|
| 40 |
-
Dockerized Agent Zero instance, mounts user data to `/a0/usr`, and tries to
|
| 41 |
-
reuse an existing Docker-compatible runtime before setting one up.
|
| 42 |
-
|
| 43 |
-
#### macOS / Linux
|
| 44 |
-
```bash
|
| 45 |
-
curl -fsSL https://bash.agent-zero.ai | bash
|
| 46 |
-
```
|
| 47 |
-
|
| 48 |
-
#### Windows PowerShell
|
| 49 |
-
```powershell
|
| 50 |
-
irm https://ps.agent-zero.ai | iex
|
| 51 |
-
```
|
| 52 |
-
|
| 53 |
-
#### Headless / scripted
|
| 54 |
-
|
| 55 |
-
For servers and automation, Quick Start mode creates one instance and exits
|
| 56 |
-
without opening menus:
|
| 57 |
-
|
| 58 |
-
```bash
|
| 59 |
-
curl -fsSL https://bash.agent-zero.ai | bash -s -- --quick-start --name agent-zero --port 5080
|
| 60 |
-
```
|
| 61 |
-
|
| 62 |
-
```powershell
|
| 63 |
-
& ([scriptblock]::Create((irm https://ps.agent-zero.ai))) -QuickStart -Name agent-zero -Port 5080
|
| 64 |
-
```
|
| 65 |
-
|
| 66 |
-
Use `--skip-runtime-setup` / `-SkipRuntimeSetup` when Docker must already be
|
| 67 |
-
working and the installer should not try to set up a runtime. See the
|
| 68 |
-
[A0 Install repository](https://github.com/agent0ai/a0-install) for all
|
| 69 |
-
installer flags.
|
| 70 |
-
|
| 71 |
-
### Docker already installed? Run this directly
|
| 72 |
-
|
| 73 |
-
```bash
|
| 74 |
-
docker run -p 80:80 -v a0_usr:/a0/usr agent0ai/agent-zero
|
| 75 |
-
```
|
| 76 |
-
|
| 77 |
-
Once the install completes, open the URL shown in your terminal or Launcher to
|
| 78 |
-
access the Web UI. Complete onboarding, add your model provider or API key, then
|
| 79 |
-
continue to [Step 3: Configure Agent Zero](#step-3-configure-agent-zero).
|
| 80 |
-
|
| 81 |
-
> [!TIP]
|
| 82 |
-
> Need Agent Zero to reach host-machine files, shell, or a host browser? Install the optional [A0 CLI Connector](../guides/a0-cli-connector.md), then run `a0` to connect your terminal to this Agent Zero instance.
|
| 83 |
-
|
| 84 |
-
---
|
| 85 |
-
|
| 86 |
-
## How to Update Agent Zero
|
| 87 |
-
|
| 88 |
-
### Self Update (Recommended)
|
| 89 |
-
|
| 90 |
-
Use the built-in updater in the Web UI:
|
| 91 |
-
|
| 92 |
-
1. Open **Settings UI -> Update** tab
|
| 93 |
-
2. Open **Self Update**
|
| 94 |
-
3. Wait for the update checker to see if you have the latest version or if there's an available update.
|
| 95 |
-
|
| 96 |
-
You'll also be prompted through the UI when a new A0 version is released. Backups are automatically managed internally during this process.
|
| 97 |
-
|
| 98 |
-
For technical details of the updater, see [Self Update](../guides/self-update.md).
|
| 99 |
-
|
| 100 |
-
### Updating from v1.20 to v2.0
|
| 101 |
-
|
| 102 |
-
Agent Zero v2.0 starts a new major release line. If your instance is on v1.20,
|
| 103 |
-
the in-app Self Update can show the newer v2.x line, but it will not apply that
|
| 104 |
-
jump inside the existing v1 Docker image. The safe path is:
|
| 105 |
-
|
| 106 |
-
1. Create a backup zip from the old v1.20 instance.
|
| 107 |
-
2. Pull the new `agent0ai/agent-zero:latest` Docker image. For the v2.0 release,
|
| 108 |
-
`latest` is the v2.0 image.
|
| 109 |
-
3. Start a new container from that image.
|
| 110 |
-
4. Restore the backup zip into the new v2.0 instance.
|
| 111 |
-
|
| 112 |
-

|
| 113 |
-
|
| 114 |
-
#### Without Agent Zero Launcher
|
| 115 |
-
|
| 116 |
-
Use this path if you manage Agent Zero directly from Docker Desktop or Docker
|
| 117 |
-
CLI.
|
| 118 |
-
|
| 119 |
-
1. Open your old v1.20 Web UI and create a backup from **Settings -> Check for Updates -> Backup & Restore -> Create Backup**. Keep the downloaded `.zip` file.
|
| 120 |
-
2. Pull the v2.0 image. In **Docker Desktop**, search for `agent0ai/agent-zero:latest` and pull that image. In **Docker CLI**, run:
|
| 121 |
-
```bash
|
| 122 |
-
docker pull agent0ai/agent-zero:latest
|
| 123 |
-
```
|
| 124 |
-
3. Start a new v2.0 container on a different host port so the old instance stays available:
|
| 125 |
-
```bash
|
| 126 |
-
docker run -d -p 50081:80 --name agent-zero-v2 -v a0_v2_usr:/a0/usr agent0ai/agent-zero:latest
|
| 127 |
-
```
|
| 128 |
-
4. Open the new v2.0 instance, complete any first-run prompts, then restore the downloaded `.zip` from **Settings -> Check for Updates -> Backup & Restore -> Restore Backup**.
|
| 129 |
-
5. Verify chats, projects, memory, settings, and custom plugins before removing the old v1.20 container.
|
| 130 |
-
|
| 131 |
-
#### With Agent Zero Launcher
|
| 132 |
-
|
| 133 |
-
Launcher gives you the same backup/restore idea from the **Instances** page.
|
| 134 |
-
|
| 135 |
-
1. Open **Instances**, choose the old v1.20 Instance, and use **Backup `/a0/usr`**.
|
| 136 |
-
2. Open **Installs**, use the **latest** card, then **Install** or **Run** the image. For the v2.0 release, **latest** is the v2.0 image.
|
| 137 |
-
3. Return to **Instances**, choose the new v2.0 Instance, and use **Restore `/a0/usr`** with the backup zip.
|
| 138 |
-
4. Open the new Instance and verify it before deleting or stopping the old v1.20 container.
|
| 139 |
-
|
| 140 |
-
Launcher keeps old and new Instances visible separately, which makes it easier
|
| 141 |
-
to compare them before cleanup.
|
| 142 |
-
|
| 143 |
-
> [!CAUTION]
|
| 144 |
-
> Do not try to solve the v1.20 -> v2.0 jump by bind-mounting the whole old
|
| 145 |
-
> `/a0` directory into a new container. Keep user data under `/a0/usr`, use the
|
| 146 |
-
> backup/restore flow, and let the new image provide the v2.0 system files.
|
| 147 |
-
|
| 148 |
-
### Updating from Pre-v0.9.8
|
| 149 |
-
|
| 150 |
-
If you are upgrading from Agent Zero v0.9.8 or earlier to v1.1 or newer, use the migration path below. Older installs were laid out differently, so the in-app Self Update is not the right tool for that jump.
|
| 151 |
-
|
| 152 |
-
1. **Backup your existing `usr/` directory** (which contains your settings, projects, memory, and custom plugins).
|
| 153 |
-
2. **Run the new install script** to set up the current Docker-based install:
|
| 154 |
-
- macOS / Linux: `curl -fsSL https://bash.agent-zero.ai | bash`
|
| 155 |
-
- Windows (PowerShell): `irm https://ps.agent-zero.ai | iex`
|
| 156 |
-
3. **Migrate your data:** After the new installation completes, copy the contents of your backed-up `usr/` directory into the new `/a0/usr/` directory created by the script.
|
| 157 |
-
4. Restart the container for the changes to take effect.
|
| 158 |
-
|
| 159 |
-
### Manual Update (Advanced)
|
| 160 |
-
|
| 161 |
-
> Use this only if Self Update is unavailable or you must manage containers yourself (for example, some custom Docker setups).
|
| 162 |
-
|
| 163 |
-
1. Keep the current container running
|
| 164 |
-
2. `docker pull agent0ai/agent-zero:latest`
|
| 165 |
-
3. Start a **new** container on a different host port, for example: `docker run -d -p 50081:80 --name agent-zero-new agent0ai/agent-zero:latest`
|
| 166 |
-
4. On the **old** instance: **Settings -> Check for Updates -> Backup & Restore -> Create Backup**
|
| 167 |
-
5. On the **new** instance: restore the downloaded backup zip
|
| 168 |
-
6. Verify chats and data, then remove the old container
|
| 169 |
-
|
| 170 |
-
> [!CAUTION]
|
| 171 |
-
> Do not delete the old container until the new one has your data.
|
| 172 |
-
|
| 173 |
-
> [!TIP]
|
| 174 |
-
> If the new instance fails to load settings, remove `/a0/usr/settings.json` and restart to regenerate default settings.
|
| 175 |
-
|
| 176 |
-
---
|
| 177 |
-
|
| 178 |
-
## Manual Installation (Advanced)
|
| 179 |
-
|
| 180 |
-
> Users should use [Quick Start (Recommended)](#quick-start-recommended) above. The steps below are for custom Docker setups, air-gapped installs, or when you cannot use the install scripts.
|
| 181 |
-
|
| 182 |
-
Follow the steps below to install Docker and run the image by hand.
|
| 183 |
-
|
| 184 |
-
### Step 1: Install Docker Desktop
|
| 185 |
-
|
| 186 |
-
Docker Desktop provides the runtime environment for Agent Zero, ensuring consistent behavior and security across platforms. The entire framework runs within a Docker container, providing isolation and easy deployment.
|
| 187 |
-
|
| 188 |
-
**Choose your operating system:**
|
| 189 |
-
|
| 190 |
-
<table>
|
| 191 |
-
<tr>
|
| 192 |
-
<td align="center" width="33%">
|
| 193 |
-
<a href="#windows-installation">
|
| 194 |
-
<img src="../res/setup/oses/windows.png" width="80" alt="Windows"/><br/>
|
| 195 |
-
<b>Windows</b>
|
| 196 |
-
</a>
|
| 197 |
-
</td>
|
| 198 |
-
<td align="center" width="33%">
|
| 199 |
-
<a href="#macos-installation">
|
| 200 |
-
<img src="../res/setup/oses/apple.png" width="80" alt="macOS"/><br/>
|
| 201 |
-
<b>macOS</b>
|
| 202 |
-
</a>
|
| 203 |
-
</td>
|
| 204 |
-
<td align="center" width="33%">
|
| 205 |
-
<a href="#linux-installation">
|
| 206 |
-
<img src="../res/setup/oses/linux.png" width="80" alt="Linux"/><br/>
|
| 207 |
-
<b>Linux</b>
|
| 208 |
-
</a>
|
| 209 |
-
</td>
|
| 210 |
-
</tr>
|
| 211 |
-
</table>
|
| 212 |
-
|
| 213 |
-
---
|
| 214 |
-
|
| 215 |
-
<a name="windows-installation"></a>
|
| 216 |
-
#### <img src="../res/setup/oses/windows.png" width="30" alt="Windows"/> Windows Installation
|
| 217 |
-
|
| 218 |
-
**1.1. Download Docker Desktop**
|
| 219 |
-
|
| 220 |
-
Go to the [Docker Desktop download page](https://www.docker.com/products/docker-desktop/) and download the Windows version (Intel/AMD is the main download button).
|
| 221 |
-
|
| 222 |
-
<img src="../res/setup/image-8.png" alt="docker download" width="200"/>
|
| 223 |
-
<br><br>
|
| 224 |
-
|
| 225 |
-
**1.2. Run the Installer**
|
| 226 |
-
|
| 227 |
-
Run the installer with default settings.
|
| 228 |
-
|
| 229 |
-
<img src="../res/setup/image-9.png" alt="docker install" width="300"/>
|
| 230 |
-
<img src="../res/setup/image-10.png" alt="docker install" width="300"/>
|
| 231 |
-
<br><br>
|
| 232 |
-
|
| 233 |
-
**1.3. Launch Docker Desktop**
|
| 234 |
-
|
| 235 |
-
Once installed, launch Docker Desktop from your Start menu or desktop shortcut.
|
| 236 |
-
|
| 237 |
-
<img src="../res/setup/image-11.png" alt="docker installed" height="100"/>
|
| 238 |
-
|
| 239 |
-
**Docker is now installed.**
|
| 240 |
-
|
| 241 |
-
Continue to [Step 2: Run Agent Zero](#step-2-run-agent-zero)
|
| 242 |
-
|
| 243 |
-
---
|
| 244 |
-
|
| 245 |
-
<a name="macos-installation"></a>
|
| 246 |
-
#### <img src="../res/setup/oses/apple.png" width="30" alt="macOS"/> macOS Installation
|
| 247 |
-
|
| 248 |
-
**1.1. Download Docker Desktop**
|
| 249 |
-
|
| 250 |
-
Go to the [Docker Desktop download page](https://www.docker.com/products/docker-desktop/) and download the macOS version (choose Apple Silicon or Intel based on your Mac).
|
| 251 |
-
|
| 252 |
-
<img src="../res/setup/image-8.png" alt="docker download" width="200"/>
|
| 253 |
-
<br><br>
|
| 254 |
-
|
| 255 |
-
**1.2. Install Docker Desktop**
|
| 256 |
-
|
| 257 |
-
Drag and drop the Docker application to your Applications folder.
|
| 258 |
-
|
| 259 |
-
<img src="../res/setup/image-12.png" alt="docker install" width="300"/>
|
| 260 |
-
<br><br>
|
| 261 |
-
|
| 262 |
-
**1.3. Launch Docker Desktop**
|
| 263 |
-
|
| 264 |
-
Open Docker Desktop from your Applications folder.
|
| 265 |
-
|
| 266 |
-
<img src="../res/setup/image-13.png" alt="docker installed" height="100"/>
|
| 267 |
-
<br><br>
|
| 268 |
-
|
| 269 |
-
**1.4. Configure Docker Socket**
|
| 270 |
-
|
| 271 |
-
> [!NOTE]
|
| 272 |
-
> **Important macOS Configuration:** In Docker Desktop's preferences (Docker menu) -> Settings -> Advanced, enable "Allow the default Docker socket to be used (requires password)."
|
| 273 |
-
|
| 274 |
-

|
| 275 |
-
|
| 276 |
-
**Docker is now installed.**
|
| 277 |
-
|
| 278 |
-
Continue to [Step 2: Run Agent Zero](#step-2-run-agent-zero)
|
| 279 |
-
|
| 280 |
-
---
|
| 281 |
-
|
| 282 |
-
<a name="linux-installation"></a>
|
| 283 |
-
#### <img src="../res/setup/oses/linux.png" width="30" alt="Linux"/> Linux Installation
|
| 284 |
-
|
| 285 |
-
**1.1. Choose Installation Method**
|
| 286 |
-
|
| 287 |
-
You can install either Docker Desktop or docker-ce (Community Edition).
|
| 288 |
-
|
| 289 |
-
**Option A: Docker Desktop (Recommended for beginners)**
|
| 290 |
-
|
| 291 |
-
Follow the instructions for your specific Linux distribution [here](https://docs.docker.com/desktop/install/linux-install/).
|
| 292 |
-
|
| 293 |
-
**Option B: docker-ce (Lightweight alternative)**
|
| 294 |
-
|
| 295 |
-
Follow the installation instructions [here](https://docs.docker.com/engine/install/).
|
| 296 |
-
|
| 297 |
-
**1.2. Post-Installation Steps (docker-ce only)**
|
| 298 |
-
|
| 299 |
-
If you installed docker-ce, add your user to the `docker` group:
|
| 300 |
-
|
| 301 |
-
```bash
|
| 302 |
-
sudo usermod -aG docker $USER
|
| 303 |
-
```
|
| 304 |
-
|
| 305 |
-
Log out and back in, then authenticate:
|
| 306 |
-
|
| 307 |
-
```bash
|
| 308 |
-
docker login
|
| 309 |
-
```
|
| 310 |
-
|
| 311 |
-
**1.3. Launch Docker**
|
| 312 |
-
|
| 313 |
-
If you installed Docker Desktop, launch it from your applications menu.
|
| 314 |
-
|
| 315 |
-
**Docker is now installed.**
|
| 316 |
-
|
| 317 |
-
> [!TIP]
|
| 318 |
-
> **Deploying on a VPS/Server?** For production deployments with reverse proxy, SSL, and domain configuration, see the [VPS Deployment Guide](vps-deployment.md).
|
| 319 |
-
|
| 320 |
-
---
|
| 321 |
-
|
| 322 |
-
### Step 2: Run Agent Zero
|
| 323 |
-
|
| 324 |
-
#### 2.1. Pull the Agent Zero Docker Image
|
| 325 |
-
|
| 326 |
-
**Using Docker Desktop GUI:**
|
| 327 |
-
|
| 328 |
-
- Search for `agent0ai/agent-zero` in Docker Desktop
|
| 329 |
-
- Click the `Pull` button
|
| 330 |
-
- The image will be downloaded to your machine in a few minutes
|
| 331 |
-
|
| 332 |
-

|
| 333 |
-
|
| 334 |
-
**Using Terminal:**
|
| 335 |
-
|
| 336 |
-
```bash
|
| 337 |
-
docker pull agent0ai/agent-zero
|
| 338 |
-
```
|
| 339 |
-
|
| 340 |
-
#### 2.2. (Optional) Map Folders for Persistence
|
| 341 |
-
|
| 342 |
-
Choose or create a folder on your computer where Agent Zero will save its data.
|
| 343 |
-
|
| 344 |
-
Setting up persistence is needed only if you want your data and files to remain available even after you delete the container.
|
| 345 |
-
|
| 346 |
-
You can pick any location you find convenient:
|
| 347 |
-
|
| 348 |
-
- **Windows:** `C:\agent-zero-data`
|
| 349 |
-
- **macOS/Linux:** `/home/user/agent-zero-data`
|
| 350 |
-
|
| 351 |
-
You can map just the `/a0/usr` directory (recommended) or individual subfolders of `/a0` to a local directory.
|
| 352 |
-
|
| 353 |
-
> [!CAUTION]
|
| 354 |
-
> Do **not** map the entire `/a0` directory: it contains the application code and can break upgrades.
|
| 355 |
-
|
| 356 |
-
> [!TIP]
|
| 357 |
-
> Choose a location that's easy to access and backup. All your Agent Zero data will be directly accessible in this directory.
|
| 358 |
-
|
| 359 |
-
#### 2.3. Run the Container
|
| 360 |
-
|
| 361 |
-
**Using Docker Desktop GUI:**
|
| 362 |
-
|
| 363 |
-
- In Docker Desktop, go to the "Images" tab
|
| 364 |
-
- Click the `Run` button next to the `agent0ai/agent-zero` image
|
| 365 |
-
- Open the "Optional settings" menu
|
| 366 |
-
- **Ensure at least one host port is mapped to container port `80`** (set host port to `0` for automatic assignment)
|
| 367 |
-
- Click the `Run` button
|
| 368 |
-
|
| 369 |
-

|
| 370 |
-

|
| 371 |
-
|
| 372 |
-
The container will start and show in the "Containers" tab:
|
| 373 |
-
|
| 374 |
-

|
| 375 |
-
|
| 376 |
-
#### 2.4. Access the Web UI
|
| 377 |
-
|
| 378 |
-
The framework will take a few seconds to initialize. Find the mapped port in Docker Desktop (shown as `<PORT>:80`) or click the port right under the container ID:
|
| 379 |
-
|
| 380 |
-

|
| 381 |
-
|
| 382 |
-
Open `http://localhost:<PORT>` in your browser. The Web UI will open - Agent Zero is ready for configuration!
|
| 383 |
-
|
| 384 |
-

|
| 385 |
-
|
| 386 |
-
> [!TIP]
|
| 387 |
-
> You can also access the Web UI by clicking the port link directly under the container ID in Docker Desktop.
|
| 388 |
-
|
| 389 |
-
> [!NOTE]
|
| 390 |
-
> After starting the container, you'll find all Agent Zero files in your chosen directory. You can access and edit these files directly on your machine, and the changes will be immediately reflected in the running container.
|
| 391 |
-
|
| 392 |
-
**Running A0 using Terminal?**
|
| 393 |
-
|
| 394 |
-
```bash
|
| 395 |
-
docker run -p 0:80 -v /path/to/your/work_dir:/a0/usr agent0ai/agent-zero
|
| 396 |
-
```
|
| 397 |
-
|
| 398 |
-
- Replace `0` with a fixed port if you prefer (e.g., `50080:80`)
|
| 399 |
-
|
| 400 |
-
---
|
| 401 |
-
|
| 402 |
-
## Step 3: Configure Agent Zero
|
| 403 |
-
|
| 404 |
-
The UI opens on the welcome screen. If model setup is missing, send a message
|
| 405 |
-
or use the setup shortcuts to choose Cloud, AI account, or Local access, then
|
| 406 |
-
select your main and utility models. For the screenshot walkthrough, see the
|
| 407 |
-
[First-Run Onboarding guide](../guides/onboarding.md).
|
| 408 |
-
|
| 409 |
-
### Settings Configuration
|
| 410 |
-
|
| 411 |
-
Agent Zero provides a comprehensive settings interface to customize various aspects of its functionality. Access the settings by clicking the "Settings" button with a gear icon in the sidebar.
|
| 412 |
-
|
| 413 |
-
### Agent Configuration
|
| 414 |
-
|
| 415 |
-
- **Agent Profile:** Select the default profile for new chats, such as `agent0`,
|
| 416 |
-
`hacker`, or `researcher`.
|
| 417 |
-
- **Memory Subdirectory:** Select the subdirectory for agent memory storage, allowing separation between different instances.
|
| 418 |
-
- **Knowledge Subdirectory:** Specify the location of custom knowledge files to enhance the agent's understanding.
|
| 419 |
-
|
| 420 |
-
See the [Agent Profiles guide](../guides/agent-profiles.md) for profile
|
| 421 |
-
switching, the Easy and Advanced editors, capability policy, and project
|
| 422 |
-
availability.
|
| 423 |
-
|
| 424 |
-
> [!NOTE]
|
| 425 |
-
> Since v0.9.7, custom prompts belong inside a specific agent profile rather
|
| 426 |
-
> than a shared `/prompts` folder. Most users should use **Manage agents** and
|
| 427 |
-
> the Agent Editor instead of editing files directly.
|
| 428 |
-
|
| 429 |
-
> [!NOTE]
|
| 430 |
-
> The Hacker profile is included in the main image. After launch, choose the **hacker** agent profile in Settings to make it the default for new chats, or switch the selected chat from the composer profile selector. The "hacker" branch is deprecated.
|
| 431 |
-
|
| 432 |
-

|
| 433 |
-
|
| 434 |
-
### Chat Model Settings
|
| 435 |
-
|
| 436 |
-
- **Provider:** Select the chat model provider (e.g., Anthropic)
|
| 437 |
-
- **Model Name:** Choose the specific model (e.g., claude-sonnet-4-5)
|
| 438 |
-
- **Context Length:** Set the maximum token limit for context window
|
| 439 |
-
- **Context Window Space:** Configure how much of the context window is dedicated to chat history
|
| 440 |
-
|
| 441 |
-

|
| 442 |
-
|
| 443 |
-
**Model naming is provider-specific.**
|
| 444 |
-
|
| 445 |
-
Use `claude-sonnet-4-5` for Anthropic, but use `anthropic/claude-sonnet-4-5` for OpenRouter. If you see "Invalid model ID," verify the provider and naming format on the provider website, or search the web for "<name-of-ai-model> model naming".
|
| 446 |
-
|
| 447 |
-
> [!TIP]
|
| 448 |
-
> **Context window tuning:** Set the total context window size first (for example, 100k), then adjust the chat history portion as a fraction of that total. A large fraction on a very large context window can still be enormous.
|
| 449 |
-
|
| 450 |
-
> [!TIP]
|
| 451 |
-
> **API URL:** URL of the API endpoint for the chat model - only needed for some providers like Ollama, LM Studio, Azure, etc.
|
| 452 |
-
|
| 453 |
-
### Utility Model Configuration
|
| 454 |
-
|
| 455 |
-
- **Provider & Model:** Select a model for utility tasks like memory organization and summarization
|
| 456 |
-
- **Temperature:** Adjust the determinism of utility responses
|
| 457 |
-
|
| 458 |
-
> [!NOTE]
|
| 459 |
-
> Utility models need to be strong enough to extract and consolidate memory reliably. Very small models (e.g., 4B) often fail at this; 70B-class models or high-quality cloud "flash/mini" models work best.
|
| 460 |
-
|
| 461 |
-
### Embedding Model Settings [Optional]
|
| 462 |
-
|
| 463 |
-
- **Provider:** Choose the embedding model provider (e.g., OpenAI)
|
| 464 |
-
- **Model Name:** Select the specific embedding model (e.g., text-embedding-3-small)
|
| 465 |
-
|
| 466 |
-
> [!NOTE]
|
| 467 |
-
> Agent Zero uses a local embedding model by default (runs on CPU), but you can switch to OpenAI embeddings like `text-embedding-3-small` or `text-embedding-3-large` if preferred.
|
| 468 |
-
|
| 469 |
-
### Built-in Voice Plugins
|
| 470 |
-
|
| 471 |
-
- Agent Zero ships Whisper STT as the built-in `_whisper_stt` plugin and Kokoro TTS as the built-in `_kokoro_tts` plugin.
|
| 472 |
-
- Docker/bootstrap remains responsible for installing the required speech dependencies such as `ffmpeg`, Kokoro, Whisper, and `soundfile`.
|
| 473 |
-
- Both plugins can be enabled or disabled independently from the Agent Plugins section in the Web UI.
|
| 474 |
-
- Whisper model size, language, message handling, and silence behavior are configured from the plugin settings screen.
|
| 475 |
-
- If `_kokoro_tts` is disabled, spoken output falls back to the browser's native speech synthesis instead of the container runtime.
|
| 476 |
-
|
| 477 |
-
### API Keys
|
| 478 |
-
|
| 479 |
-
Configure API keys for various service providers directly within the Web UI. Click `Save` to confirm your settings.
|
| 480 |
-
|
| 481 |
-
> [!NOTE]
|
| 482 |
-
> **OpenAI API vs Plus subscription:** A ChatGPT Plus subscription does not include API credits. You must provide a separate API key for OpenAI usage in Agent Zero.
|
| 483 |
-
|
| 484 |
-
> [!TIP]
|
| 485 |
-
> For OpenAI-compatible providers (e.g., custom gateways or Z.AI/GLM), add the API key under **External Services -> Other OpenAI-compatible API keys**, then select **OpenAI Compatible** as the provider in model settings.
|
| 486 |
-
|
| 487 |
-
> [!CAUTION]
|
| 488 |
-
> **GitHub Copilot Provider:** When using the GitHub Copilot provider, after selecting the model and entering your first prompt, the OAuth login procedure will begin. You'll find the authentication code and link in the output logs. Complete the authentication process by following the provided link and entering the code, then you may continue using Agent Zero.
|
| 489 |
-
|
| 490 |
-
### Authentication
|
| 491 |
-
|
| 492 |
-
- **UI Login:** Set username for web interface access
|
| 493 |
-
- **UI Password:** Configure password for web interface security
|
| 494 |
-
- **Root Password:** Manage Docker container root password for SSH access
|
| 495 |
-
|
| 496 |
-

|
| 497 |
-
|
| 498 |
-
### Development Settings
|
| 499 |
-
|
| 500 |
-
- **RFC Parameters (local instances only):** Configure URLs and ports for remote function calls between instances
|
| 501 |
-
- **RFC Password:** Configure password for remote function calls
|
| 502 |
-
|
| 503 |
-
Learn more about Remote Function Calls in the [Development Setup guide](dev-setup.md#step-6-configure-ssh-and-rfc-connection).
|
| 504 |
-
|
| 505 |
-
> [!IMPORTANT]
|
| 506 |
-
> Always keep your API keys and passwords secure.
|
| 507 |
-
|
| 508 |
-
> [!NOTE]
|
| 509 |
-
> On Windows host installs (non-Docker), you must use RFC to run shell code on the host system. The Docker runtime handles this automatically.
|
| 510 |
-
|
| 511 |
-
---
|
| 512 |
-
|
| 513 |
-
## Choosing Your LLMs
|
| 514 |
-
|
| 515 |
-
The Settings page is the control center for selecting the Large Language Models (LLMs) that power Agent Zero. You can choose different LLMs for different roles:
|
| 516 |
-
|
| 517 |
-
| LLM Role | Description |
|
| 518 |
-
| --- | --- |
|
| 519 |
-
| `chat_llm` | This is the primary LLM used for conversations, agent reasoning, and tool use. Vision support controls image understanding. |
|
| 520 |
-
| `utility_llm` | This LLM handles internal tasks like summarizing messages, managing memory, and processing internal prompts. Using a smaller, less expensive model here can improve efficiency. |
|
| 521 |
-
| `embedding_llm` | The embedding model shipped with A0 runs on CPU and is responsible for generating embeddings used for memory retrieval and knowledge base lookups. Changing the `embedding_llm` will re-index all of A0's memory. |
|
| 522 |
-
|
| 523 |
-
**How to Change:**
|
| 524 |
-
|
| 525 |
-
1. Open Settings page in the Web UI.
|
| 526 |
-
2. Choose the provider for the LLM for each role (Main Model, Utility Model, Embedding Model) and write the model name.
|
| 527 |
-
3. Click "Save" to apply the changes.
|
| 528 |
-
|
| 529 |
-
> [!NOTE]
|
| 530 |
-
> The built-in Browser does not have a separate default model slot. The main agent decides when to call the direct `browser` tool. Browser settings can optionally choose a Browser LLM preset for Browser-owned helper operations.
|
| 531 |
-
|
| 532 |
-
### Important Considerations
|
| 533 |
-
|
| 534 |
-
#### Model Naming by Provider
|
| 535 |
-
|
| 536 |
-
Use the naming format required by your selected provider:
|
| 537 |
-
|
| 538 |
-
| Provider | Model Name Format | Example |
|
| 539 |
-
| --- | --- | --- |
|
| 540 |
-
| OpenAI | Model name only | `claude-sonnet-4-5` |
|
| 541 |
-
| OpenRouter | Provider prefix mostly required | `anthropic/claude-sonnet-4-5` |
|
| 542 |
-
| Ollama | Model name only | `gpt-oss:20b` |
|
| 543 |
-
| oMLX | API-visible model name from `/v1/models` | `Qwen3-0.6B-4bit` |
|
| 544 |
-
| llama.cpp | API-visible model name from `/v1/models` or `--alias` | `local-gguf` |
|
| 545 |
-
| vLLM | Hugging Face model ID or served model alias | `Qwen/Qwen2.5-1.5B-Instruct` |
|
| 546 |
-
|
| 547 |
-
> [!TIP]
|
| 548 |
-
> If you see "Invalid model ID," verify the provider and naming format on the provider website, or search the web for "<name-of-ai-model> model naming".
|
| 549 |
-
|
| 550 |
-
#### Local Model Server Addresses From Docker
|
| 551 |
-
|
| 552 |
-
When Agent Zero runs in Docker, `localhost` and `127.0.0.1` inside an API base URL mean the Agent Zero container, not your host machine. For a model server running on the host, use `http://host.docker.internal:<port>` when available, or the Docker host gateway address such as `http://172.17.0.1:<port>` on the default Linux bridge.
|
| 553 |
-
|
| 554 |
-
If the model server only listens on host loopback, for example `127.0.0.1:<port>`, the container still cannot reach it through the gateway. Configure the local server to listen on a Docker-reachable address such as `0.0.0.0`, and keep that port limited to trusted clients.
|
| 555 |
-
|
| 556 |
-
#### Context Window & Memory Split
|
| 557 |
-
|
| 558 |
-
- Set the **total context window** (e.g., 100k) first.
|
| 559 |
-
- Then tune the **chat history portion** as a fraction of that total.
|
| 560 |
-
- Extremely large totals can make even small fractions very large; adjust thoughtfully.
|
| 561 |
-
|
| 562 |
-
#### Utility Model Guidance
|
| 563 |
-
|
| 564 |
-
- Utility models handle summarization and memory extraction.
|
| 565 |
-
- Very small models (about 4B) usually fail at reliable context extraction.
|
| 566 |
-
- Aim for ~70B class models or strong cloud "flash/mini" models for better results.
|
| 567 |
-
|
| 568 |
-
#### Reasoning/Thinking Models
|
| 569 |
-
|
| 570 |
-
- Reasoning can increase cost and latency. Some models perform better **without** reasoning.
|
| 571 |
-
- If a model supports it, disable reasoning via provider-specific parameters (e.g., Venice `disable_thinking=true`).
|
| 572 |
-
|
| 573 |
-
---
|
| 574 |
-
|
| 575 |
-
## Installing and Using oMLX (Apple Silicon Local Models)
|
| 576 |
-
|
| 577 |
-
oMLX is a local inference server for Apple Silicon Macs. It serves MLX models through an OpenAI-compatible API and supports chat, embeddings, and model listing endpoints.
|
| 578 |
-
|
| 579 |
-
> [!NOTE]
|
| 580 |
-
> oMLX requires Apple Silicon and macOS 15+. On 16 GB machines, start with small quantized MLX models.
|
| 581 |
-
|
| 582 |
-
### macOS oMLX Installation
|
| 583 |
-
|
| 584 |
-
**Using Homebrew:**
|
| 585 |
-
|
| 586 |
-
```bash
|
| 587 |
-
brew tap jundot/omlx https://github.com/jundot/omlx
|
| 588 |
-
brew install omlx
|
| 589 |
-
omlx start
|
| 590 |
-
```
|
| 591 |
-
|
| 592 |
-
**Using the macOS App:**
|
| 593 |
-
|
| 594 |
-
Download the oMLX app from the [official website](https://omlx.ai/) and follow the welcome flow to choose a model directory, start the server, and download or discover models.
|
| 595 |
-
|
| 596 |
-
By default, oMLX serves its OpenAI-compatible API at `http://localhost:8000/v1`.
|
| 597 |
-
|
| 598 |
-
To run a foreground server with oMLX's paged SSD cache enabled:
|
| 599 |
-
|
| 600 |
-
```bash
|
| 601 |
-
omlx serve --model-dir ~/.omlx/models --paged-ssd-cache-dir ~/.omlx/cache
|
| 602 |
-
```
|
| 603 |
-
|
| 604 |
-
### Configuring oMLX in Agent Zero
|
| 605 |
-
|
| 606 |
-
1. Start oMLX and make sure at least one model is available in the oMLX dashboard or model directory.
|
| 607 |
-
2. In Agent Zero Settings, choose **oMLX** as the Chat model, Utility model, or Embedding model provider.
|
| 608 |
-
3. Use the model name shown by oMLX's model list or dashboard.
|
| 609 |
-
4. Agent Zero includes Docker-friendly defaults for oMLX on the host at `http://host.docker.internal:8000/v1`. Override the API base URL only if your oMLX server runs somewhere else.
|
| 610 |
-
5. Click `Save` to confirm your settings.
|
| 611 |
-
|
| 612 |
-
> [!NOTE]
|
| 613 |
-
> If Agent Zero runs in Docker and oMLX runs on the Mac host, ensure port **8000** is reachable from the container. The shipped Docker Compose file maps `host.docker.internal` to the host gateway for Linux Docker. Docker Desktop for macOS provides this hostname automatically.
|
| 614 |
-
|
| 615 |
-
---
|
| 616 |
-
|
| 617 |
-
## Installing and Using llama.cpp (GGUF Local Models)
|
| 618 |
-
|
| 619 |
-
llama.cpp provides `llama-server`, a lightweight OpenAI-compatible HTTP server for GGUF models. Agent Zero talks to it through the same `/v1` API used by OpenAI-compatible clients.
|
| 620 |
-
|
| 621 |
-
### macOS llama.cpp Installation
|
| 622 |
-
|
| 623 |
-
**Using Homebrew:**
|
| 624 |
-
|
| 625 |
-
```bash
|
| 626 |
-
brew install llama.cpp
|
| 627 |
-
```
|
| 628 |
-
|
| 629 |
-
Start a server with a downloaded GGUF model:
|
| 630 |
-
|
| 631 |
-
```bash
|
| 632 |
-
llama-server -m ~/models/model.gguf --port 8080 --alias local-gguf
|
| 633 |
-
```
|
| 634 |
-
|
| 635 |
-
By default, Agent Zero expects llama.cpp at `http://host.docker.internal:8080/v1`. The model name can be the model path returned by `/v1/models`, but using `--alias` gives you a short stable name such as `local-gguf`.
|
| 636 |
-
|
| 637 |
-
### Configuring llama.cpp in Agent Zero
|
| 638 |
-
|
| 639 |
-
1. Start `llama-server` and confirm `http://localhost:8080/v1/models` returns your model.
|
| 640 |
-
2. In Agent Zero Settings, choose **llama.cpp** as the Chat model, Utility model, or Embedding model provider.
|
| 641 |
-
3. Use the model ID shown by `/v1/models`, or the alias you passed with `--alias`.
|
| 642 |
-
4. Override the API base URL only if you started `llama-server` on another host or port.
|
| 643 |
-
5. Click `Save` to confirm your settings.
|
| 644 |
-
|
| 645 |
-
> [!NOTE]
|
| 646 |
-
> If Agent Zero runs in Docker and cannot reach a host-side `llama-server`, start the server on an address Docker can reach, for example `--host 0.0.0.0`, and keep the port firewalled to trusted clients.
|
| 647 |
-
|
| 648 |
-
---
|
| 649 |
-
|
| 650 |
-
## Installing and Using vLLM (Local OpenAI-Compatible Serving)
|
| 651 |
-
|
| 652 |
-
vLLM is a high-throughput local inference server with an OpenAI-compatible API. It is most common on Linux GPU hosts, and can also run on Apple Silicon through the vLLM Apple Silicon path or vLLM-Metal.
|
| 653 |
-
|
| 654 |
-
For Apple Silicon Macs, install and activate vLLM-Metal:
|
| 655 |
-
|
| 656 |
-
```bash
|
| 657 |
-
curl -fsSL https://raw.githubusercontent.com/vllm-project/vllm-metal/main/install.sh | bash
|
| 658 |
-
source ~/.venv-vllm-metal/bin/activate
|
| 659 |
-
```
|
| 660 |
-
|
| 661 |
-
Start a basic OpenAI-compatible server:
|
| 662 |
-
|
| 663 |
-
```bash
|
| 664 |
-
vllm serve Qwen/Qwen2.5-1.5B-Instruct --host 0.0.0.0 --port 8000
|
| 665 |
-
```
|
| 666 |
-
|
| 667 |
-
By default, Agent Zero expects vLLM at `http://host.docker.internal:8000/v1`, matching vLLM's default HTTP port. If another local provider already uses port 8000, start vLLM on another port and update Agent Zero's API base, for example `http://host.docker.internal:8001/v1`.
|
| 668 |
-
|
| 669 |
-
### Configuring vLLM in Agent Zero
|
| 670 |
-
|
| 671 |
-
1. Start vLLM and confirm `http://localhost:8000/v1/models` returns the served model.
|
| 672 |
-
2. In Agent Zero Settings, choose **vLLM** as the Chat model, Utility model, or Embedding model provider.
|
| 673 |
-
3. Use the model ID returned by vLLM's model list endpoint.
|
| 674 |
-
4. If you started vLLM with `--api-key`, enter the same key in the advanced provider settings or environment.
|
| 675 |
-
5. Click `Save` to confirm your settings.
|
| 676 |
-
|
| 677 |
-
> [!NOTE]
|
| 678 |
-
> vLLM serves one model at a time by default. Use a generation model for Chat and Utility slots, and a separate embedding-capable vLLM server if you want vLLM embeddings.
|
| 679 |
-
|
| 680 |
-
---
|
| 681 |
-
|
| 682 |
-
## Installing and Using Ollama (Local Models)
|
| 683 |
-
|
| 684 |
-
Ollama is a powerful tool that allows you to run various large language models locally.
|
| 685 |
-
|
| 686 |
-
---
|
| 687 |
-
|
| 688 |
-
<a name="windows-ollama-installation"></a>
|
| 689 |
-
### <img src="../res/setup/oses/windows.png" width="30" alt="Windows"/> Windows Ollama Installation
|
| 690 |
-
|
| 691 |
-
Download and install Ollama from the official website:
|
| 692 |
-
|
| 693 |
-
<button>[Download Ollama Setup](https://ollama.com/download/OllamaSetup.exe)</button>
|
| 694 |
-
|
| 695 |
-
Once installed, continue to [Pulling Models](#pulling-models).
|
| 696 |
-
|
| 697 |
-
---
|
| 698 |
-
|
| 699 |
-
<a name="macos-ollama-installation"></a>
|
| 700 |
-
### <img src="../res/setup/oses/apple.png" width="30" alt="macOS"/> macOS Ollama Installation
|
| 701 |
-
|
| 702 |
-
**Using Homebrew:**
|
| 703 |
-
|
| 704 |
-
```bash
|
| 705 |
-
brew install ollama
|
| 706 |
-
```
|
| 707 |
-
|
| 708 |
-
**Using Installer:**
|
| 709 |
-
|
| 710 |
-
Download from the [official website](https://ollama.com/).
|
| 711 |
-
|
| 712 |
-
Once installed, continue to [Pulling Models](#pulling-models).
|
| 713 |
-
|
| 714 |
-
---
|
| 715 |
-
|
| 716 |
-
<a name="linux-ollama-installation"></a>
|
| 717 |
-
### <img src="../res/setup/oses/linux.png" width="30" alt="Linux"/> Linux Ollama Installation
|
| 718 |
-
|
| 719 |
-
Run the installation script:
|
| 720 |
-
|
| 721 |
-
```bash
|
| 722 |
-
curl -fsSL https://ollama.com/install.sh | sh
|
| 723 |
-
```
|
| 724 |
-
|
| 725 |
-
Once installed, continue to [Pulling Models](#pulling-models).
|
| 726 |
-
|
| 727 |
-
---
|
| 728 |
-
|
| 729 |
-
### Pulling Models
|
| 730 |
-
|
| 731 |
-
**Finding Model Names:**
|
| 732 |
-
|
| 733 |
-
Visit the [Ollama model library](https://ollama.com/library) for a list of available models and their corresponding names. Ollama models are referenced by **model name only** (for example, `llama3.2`).
|
| 734 |
-
|
| 735 |
-
**Pull a model:**
|
| 736 |
-
|
| 737 |
-
```bash
|
| 738 |
-
ollama pull <model-name>
|
| 739 |
-
```
|
| 740 |
-
|
| 741 |
-
Replace `<model-name>` with the name of the model you want to use. For example: `ollama pull mistral-large`
|
| 742 |
-
|
| 743 |
-
### Configuring Ollama in Agent Zero
|
| 744 |
-
|
| 745 |
-
1. Once you've downloaded your model(s), select it in the Settings page of the GUI.
|
| 746 |
-
2. Within the Chat model, Utility model, or Embedding model section, choose **Ollama** as provider.
|
| 747 |
-
3. Write your model code as expected by Ollama, in the format `llama3.2` or `qwen2.5:7b`
|
| 748 |
-
4. Agent Zero includes Docker-friendly defaults for Ollama on the host at `http://host.docker.internal:11434`. Override the API base URL only if your Ollama server runs somewhere else.
|
| 749 |
-
5. Click `Save` to confirm your settings.
|
| 750 |
-
|
| 751 |
-

|
| 752 |
-
|
| 753 |
-
> [!NOTE]
|
| 754 |
-
> If Agent Zero runs in Docker and Ollama runs on the host, ensure port **11434** is reachable from the container. The shipped Docker Compose file maps `host.docker.internal` to the host gateway for Linux Docker. If both services are in the same Docker network, you can use `http://<container_name>:11434` instead of `host.docker.internal`.
|
| 755 |
-
|
| 756 |
-
### Managing Downloaded Models
|
| 757 |
-
|
| 758 |
-
**Listing downloaded models:**
|
| 759 |
-
|
| 760 |
-
```bash
|
| 761 |
-
ollama list
|
| 762 |
-
```
|
| 763 |
-
|
| 764 |
-
**Removing a model:**
|
| 765 |
-
|
| 766 |
-
```bash
|
| 767 |
-
ollama rm <model-name>
|
| 768 |
-
```
|
| 769 |
-
|
| 770 |
-
> [!TIP]
|
| 771 |
-
> Experiment with different model combinations to find the balance of performance and cost that best suits your needs. E.g., faster and lower latency LLMs will help, and you can also use `faiss_gpu` instead of `faiss_cpu` for the memory.
|
| 772 |
-
|
| 773 |
-
---
|
| 774 |
-
|
| 775 |
-
## Using Agent Zero on Your Mobile Device
|
| 776 |
-
|
| 777 |
-
Agent Zero can be accessed from mobile devices and other computers using the built-in **Tunnel feature**.
|
| 778 |
-
|
| 779 |
-
### Recommended: Using Tunnel (Remote Access)
|
| 780 |
-
|
| 781 |
-
The Tunnel feature allows secure access to your Agent Zero instance from anywhere:
|
| 782 |
-
|
| 783 |
-
1. Open Settings in the Web UI
|
| 784 |
-
2. Navigate to the **External Services** tab
|
| 785 |
-
3. Click on **Flare Tunnel** in the navigation menu
|
| 786 |
-
4. Click **Create Tunnel** to generate a secure HTTPS URL
|
| 787 |
-
5. Share this URL to access Agent Zero from any device
|
| 788 |
-
|
| 789 |
-
> [!IMPORTANT]
|
| 790 |
-
> **Security:** Always set a username and password in Settings -> Authentication before creating a tunnel to secure your instance on the internet.
|
| 791 |
-
|
| 792 |
-
For complete details on tunnel configuration and security considerations, see the [Remote Access via Tunneling](../guides/usage.md#remote-access-via-tunneling) section in the Usage Guide.
|
| 793 |
-
|
| 794 |
-
### Alternative: Local Network Access
|
| 795 |
-
|
| 796 |
-
If you prefer to keep access limited to your local network:
|
| 797 |
-
|
| 798 |
-
1. Find the mapped port in Docker Desktop (format: `<PORT>:80`, e.g., `32771:80`)
|
| 799 |
-
2. Access from the same computer: `http://localhost:<PORT>`
|
| 800 |
-
3. Access from other devices on the network: `http://<YOUR_COMPUTER_IP>:<PORT>`
|
| 801 |
-
|
| 802 |
-
> [!TIP]
|
| 803 |
-
> Find your computer's IP address with `ipconfig` (Windows) or `ifconfig`/`ip addr` (macOS/Linux). It's usually in the format `192.168.x.x` or `10.0.x.x`.
|
| 804 |
-
|
| 805 |
-
For developers or users who need to run Agent Zero directly on their system, see the [In-Depth Guide for Full Binaries Installation](dev-setup.md).
|
| 806 |
-
|
| 807 |
-
---
|
| 808 |
-
|
| 809 |
-
## Advanced: Automated Configuration via Environment Variables
|
| 810 |
-
|
| 811 |
-
Agent Zero settings can be automatically configured using environment variables with the `A0_SET_` prefix in your `.env` file. This enables automated deployments without manual configuration.
|
| 812 |
-
|
| 813 |
-
**Usage:**
|
| 814 |
-
|
| 815 |
-
Add variables to your `.env` file in the format:
|
| 816 |
-
|
| 817 |
-
```env
|
| 818 |
-
A0_SET_{setting_name}={value}
|
| 819 |
-
```
|
| 820 |
-
|
| 821 |
-
**Examples:**
|
| 822 |
-
|
| 823 |
-
```env
|
| 824 |
-
# Model configuration
|
| 825 |
-
A0_SET_chat_model_provider=anthropic
|
| 826 |
-
A0_SET_chat_model_name=claude-3-5-sonnet-20241022
|
| 827 |
-
A0_SET_chat_model_ctx_length=200000
|
| 828 |
-
|
| 829 |
-
# Memory settings
|
| 830 |
-
A0_SET_memory_recall_enabled=true
|
| 831 |
-
A0_SET_memory_recall_interval=5
|
| 832 |
-
|
| 833 |
-
# Agent configuration
|
| 834 |
-
A0_SET_agent_profile=custom
|
| 835 |
-
A0_SET_agent_memory_subdir=production
|
| 836 |
-
```
|
| 837 |
-
|
| 838 |
-
**Docker usage:**
|
| 839 |
-
|
| 840 |
-
When running Docker, you can pass these as environment variables:
|
| 841 |
-
|
| 842 |
-
```bash
|
| 843 |
-
docker run -p 50080:80 \
|
| 844 |
-
-e A0_SET_chat_model_provider=anthropic \
|
| 845 |
-
-e A0_SET_chat_model_name=claude-3-5-sonnet-20241022 \
|
| 846 |
-
agent0ai/agent-zero
|
| 847 |
-
```
|
| 848 |
-
|
| 849 |
-
**Notes:**
|
| 850 |
-
|
| 851 |
-
- These provide initial default values when settings.json doesn't exist or when new settings are added to the application. Once a value is saved in settings.json, it takes precedence over these environment variables.
|
| 852 |
-
- Sensitive settings (API keys, passwords) use their existing environment variables
|
| 853 |
-
- Container/process restart required for changes to take effect
|
| 854 |
-
|
| 855 |
-
---
|
| 856 |
-
|
| 857 |
-
### Manual Migration (Legacy or Non-Docker)
|
| 858 |
-
|
| 859 |
-
If you are migrating from older, non-Docker setups, A0 handles the migration of legacy folders and files automatically at runtime. The right place to save your files and directories is `a0/usr`.
|
| 860 |
-
|
| 861 |
-
## Conclusion
|
| 862 |
-
|
| 863 |
-
After following the instructions for your specific operating system, you should have Agent Zero successfully installed and running. You can now start exploring the framework's capabilities and experimenting with creating your own intelligent agents.
|
| 864 |
-
|
| 865 |
-
**Next Steps:**
|
| 866 |
-
|
| 867 |
-
- For production server deployments, see the [VPS Deployment Guide](vps-deployment.md)
|
| 868 |
-
- For development setup and extensions, see the [Development Setup Guide](dev-setup.md)
|
| 869 |
-
- For remote access via tunnel, see [Remote Access via Tunneling](../guides/usage.md#remote-access-via-tunneling)
|
| 870 |
-
|
| 871 |
-
If you encounter any issues during the installation process, please consult the [Troubleshooting section](../guides/troubleshooting.md) of this documentation or refer to the Agent Zero [Skool](https://www.skool.com/agent-zero) or [Discord](https://discord.gg/B8KZKNsPpj) community for assistance.
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:22679137b4317a0dafc352dca421aa13cd208db65b9b9deb843c6198730cfd6f
|
| 3 |
+
size 35606
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
docs/setup/vps-deployment.md
CHANGED
|
@@ -1,770 +1,3 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
> **Author:** Auto-generated from deployment experience
|
| 5 |
-
> **Last Updated:** December 21 2025
|
| 6 |
-
> **Compatibility:** Docker-capable Linux servers (AlmaLinux, CentOS, Rocky, Ubuntu, Debian)
|
| 7 |
-
|
| 8 |
-
---
|
| 9 |
-
|
| 10 |
-
## Table of Contents
|
| 11 |
-
|
| 12 |
-
1. [Prerequisites](#prerequisites)
|
| 13 |
-
2. [Docker Installation](#docker-installation)
|
| 14 |
-
3. [Agent Zero Container Deployment](#agent-zero-container-deployment)
|
| 15 |
-
4. [Apache Reverse Proxy Configuration](#apache-reverse-proxy-configuration)
|
| 16 |
-
5. [SSL/TLS Configuration](#ssltls-configuration)
|
| 17 |
-
6. [Authentication Setup](#authentication-setup)
|
| 18 |
-
7. [Domain & DNS Setup](#domain-dns-setup)
|
| 19 |
-
8. [Verification & Testing](#verification-testing)
|
| 20 |
-
9. [Troubleshooting](#troubleshooting)
|
| 21 |
-
10. [Maintenance & Updates](#maintenance-updates)
|
| 22 |
-
11. [Quick Reference](#quick-reference)
|
| 23 |
-
|
| 24 |
-
---
|
| 25 |
-
|
| 26 |
-
## Prerequisites
|
| 27 |
-
|
| 28 |
-
### Server Requirements
|
| 29 |
-
|
| 30 |
-
| Requirement | Minimum | Recommended |
|
| 31 |
-
|-------------|---------|-------------|
|
| 32 |
-
| **RAM** | 2 GB | 4+ GB |
|
| 33 |
-
| **Storage** | 20 GB | 50+ GB |
|
| 34 |
-
| **CPU** | 1 vCPU | 2+ vCPU |
|
| 35 |
-
| **OS** | Linux (64-bit) | AlmaLinux 9, Ubuntu 22.04+ |
|
| 36 |
-
| **Network** | Static IP | Dedicated IP with reverse DNS |
|
| 37 |
-
|
| 38 |
-
### Required Access
|
| 39 |
-
|
| 40 |
-
- Root or sudo access to the server
|
| 41 |
-
- SSH access (preferably on non-standard port)
|
| 42 |
-
- Domain/subdomain with DNS control
|
| 43 |
-
- SSL certificate (Let's Encrypt or commercial)
|
| 44 |
-
|
| 45 |
-
### Software Dependencies
|
| 46 |
-
|
| 47 |
-
- Docker Engine 24.0+
|
| 48 |
-
- Apache 2.4+ with mod_proxy, mod_proxy_http, mod_proxy_wstunnel, mod_ssl, mod_rewrite
|
| 49 |
-
- curl, git (optional)
|
| 50 |
-
|
| 51 |
-
---
|
| 52 |
-
|
| 53 |
-
## Docker Installation
|
| 54 |
-
|
| 55 |
-
> [!NOTE]
|
| 56 |
-
> For detailed Docker installation instructions and alternative methods, see the [Linux Installation section](installation.md#linux-installation) in the main installation guide.
|
| 57 |
-
|
| 58 |
-
### Method A: Debian/Ubuntu Systems
|
| 59 |
-
|
| 60 |
-
```bash
|
| 61 |
-
# Update package index
|
| 62 |
-
apt-get update
|
| 63 |
-
|
| 64 |
-
# Install prerequisites
|
| 65 |
-
apt-get install -y ca-certificates curl gnupg
|
| 66 |
-
|
| 67 |
-
# Add Docker's official GPG key
|
| 68 |
-
install -m 0755 -d /etc/apt/keyrings
|
| 69 |
-
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
|
| 70 |
-
chmod a+r /etc/apt/keyrings/docker.gpg
|
| 71 |
-
|
| 72 |
-
# Set up repository
|
| 73 |
-
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
|
| 74 |
-
|
| 75 |
-
# Install Docker
|
| 76 |
-
apt-get update
|
| 77 |
-
apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
|
| 78 |
-
|
| 79 |
-
# Start and enable Docker
|
| 80 |
-
systemctl enable docker
|
| 81 |
-
systemctl start docker
|
| 82 |
-
```
|
| 83 |
-
|
| 84 |
-
### Method B: AlmaLinux/Rocky/CentOS/RHEL Systems
|
| 85 |
-
|
| 86 |
-
```bash
|
| 87 |
-
# Install required packages
|
| 88 |
-
dnf -y install dnf-plugins-core
|
| 89 |
-
|
| 90 |
-
# Add Docker repository (use CentOS repo for AlmaLinux/Rocky)
|
| 91 |
-
dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
|
| 92 |
-
|
| 93 |
-
# Install Docker
|
| 94 |
-
dnf -y install docker-ce docker-ce-cli containerd.io docker-compose-plugin
|
| 95 |
-
|
| 96 |
-
# Start and enable Docker
|
| 97 |
-
systemctl enable docker
|
| 98 |
-
systemctl start docker
|
| 99 |
-
```
|
| 100 |
-
|
| 101 |
-
### Method C: Generic (Convenience Script)
|
| 102 |
-
|
| 103 |
-
> ⚠️ **Note:** May not work on all distributions (e.g., AlmaLinux)
|
| 104 |
-
|
| 105 |
-
```bash
|
| 106 |
-
curl -fsSL https://get.docker.com -o get-docker.sh
|
| 107 |
-
sh get-docker.sh
|
| 108 |
-
systemctl enable docker
|
| 109 |
-
systemctl start docker
|
| 110 |
-
```
|
| 111 |
-
|
| 112 |
-
### Verify Docker Installation
|
| 113 |
-
|
| 114 |
-
```bash
|
| 115 |
-
docker --version
|
| 116 |
-
docker run hello-world
|
| 117 |
-
```
|
| 118 |
-
|
| 119 |
-
---
|
| 120 |
-
|
| 121 |
-
## Agent Zero Container Deployment
|
| 122 |
-
|
| 123 |
-
### Step 1: Create Directory Structure
|
| 124 |
-
|
| 125 |
-
```bash
|
| 126 |
-
# Choose your installation path
|
| 127 |
-
A0_NAME="a0-instance" # Change this to your instance name
|
| 128 |
-
A0_PATH="/opt/${A0_NAME}"
|
| 129 |
-
|
| 130 |
-
# Create directories
|
| 131 |
-
mkdir -p ${A0_PATH}
|
| 132 |
-
mkdir -p ${A0_PATH}/work_dir
|
| 133 |
-
mkdir -p ${A0_PATH}/memory
|
| 134 |
-
mkdir -p ${A0_PATH}/logs
|
| 135 |
-
```
|
| 136 |
-
|
| 137 |
-
### Step 2: Create Environment Configuration
|
| 138 |
-
|
| 139 |
-
```bash
|
| 140 |
-
# Create .env file with authentication
|
| 141 |
-
cat > ${A0_PATH}/.env << 'EOF'
|
| 142 |
-
# Agent Zero Configuration
|
| 143 |
-
# Authentication (REQUIRED for web access)
|
| 144 |
-
AUTH_LOGIN=your_username_here
|
| 145 |
-
AUTH_PASSWORD=your_secure_password_here
|
| 146 |
-
|
| 147 |
-
# Optional: Additional configuration
|
| 148 |
-
# See Agent Zero documentation for all options
|
| 149 |
-
EOF
|
| 150 |
-
```
|
| 151 |
-
|
| 152 |
-
> ⚠️ **CRITICAL:** `AUTH_LOGIN` is the **username**, not a boolean!
|
| 153 |
-
> - ✅ Correct: `AUTH_LOGIN=admin`
|
| 154 |
-
> - ❌ Wrong: `AUTH_LOGIN=true`
|
| 155 |
-
|
| 156 |
-
### Step 3: Choose Host Port
|
| 157 |
-
|
| 158 |
-
| Port | Use Case |
|
| 159 |
-
|------|----------|
|
| 160 |
-
| `50080` | Standard/recommended for reverse proxy setups |
|
| 161 |
-
| `50081`, `50082`... | Additional instances on same server |
|
| 162 |
-
| `80` | Direct access (not recommended for production) |
|
| 163 |
-
|
| 164 |
-
### Step 4: Pull and Run Container
|
| 165 |
-
|
| 166 |
-
```bash
|
| 167 |
-
# Set variables
|
| 168 |
-
A0_NAME="a0-instance"
|
| 169 |
-
A0_PATH="/opt/${A0_NAME}"
|
| 170 |
-
A0_PORT="50080"
|
| 171 |
-
|
| 172 |
-
# Pull latest image
|
| 173 |
-
docker pull agent0ai/agent-zero:latest
|
| 174 |
-
|
| 175 |
-
# Run container
|
| 176 |
-
docker run -d --name ${A0_NAME} --restart unless-stopped -p ${A0_PORT}:80 -v ${A0_PATH}/.env:/a0/.env -v ${A0_PATH}/usr:/a0/usr agent0ai/agent-zero:latest
|
| 177 |
-
```
|
| 178 |
-
|
| 179 |
-
### Step 5: Verify Container
|
| 180 |
-
|
| 181 |
-
```bash
|
| 182 |
-
# Check container is running
|
| 183 |
-
docker ps | grep ${A0_NAME}
|
| 184 |
-
|
| 185 |
-
# Check logs
|
| 186 |
-
docker logs ${A0_NAME}
|
| 187 |
-
|
| 188 |
-
# Test local access
|
| 189 |
-
curl -I http://127.0.0.1:${A0_PORT}/
|
| 190 |
-
```
|
| 191 |
-
|
| 192 |
-
Expected response: `HTTP/1.1 302 FOUND` with `Location: /login` (if auth enabled)
|
| 193 |
-
|
| 194 |
-
---
|
| 195 |
-
|
| 196 |
-
## Apache Reverse Proxy Configuration
|
| 197 |
-
|
| 198 |
-
### Required Apache Modules
|
| 199 |
-
|
| 200 |
-
```bash
|
| 201 |
-
# Debian/Ubuntu
|
| 202 |
-
a2enmod proxy proxy_http proxy_wstunnel ssl rewrite headers
|
| 203 |
-
systemctl restart apache2
|
| 204 |
-
|
| 205 |
-
# AlmaLinux/CentOS (usually pre-loaded)
|
| 206 |
-
httpd -M | grep -E "proxy|rewrite|ssl"
|
| 207 |
-
```
|
| 208 |
-
|
| 209 |
-
### Configuration for Standard Apache (Debian/Ubuntu)
|
| 210 |
-
|
| 211 |
-
Create `/etc/apache2/sites-available/a0-instance.conf`:
|
| 212 |
-
|
| 213 |
-
```apache
|
| 214 |
-
# Agent Zero Reverse Proxy Configuration
|
| 215 |
-
# Instance: a0-instance
|
| 216 |
-
# Domain: a0.example.com
|
| 217 |
-
|
| 218 |
-
# HTTP - Redirect to HTTPS
|
| 219 |
-
<VirtualHost *:80>
|
| 220 |
-
ServerName a0.example.com
|
| 221 |
-
ServerAlias www.a0.example.com
|
| 222 |
-
|
| 223 |
-
RewriteEngine On
|
| 224 |
-
RewriteCond %{HTTPS} off
|
| 225 |
-
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
|
| 226 |
-
</VirtualHost>
|
| 227 |
-
|
| 228 |
-
# HTTPS - Proxy to Container
|
| 229 |
-
<VirtualHost *:443>
|
| 230 |
-
ServerName a0.example.com
|
| 231 |
-
ServerAlias www.a0.example.com
|
| 232 |
-
ServerAdmin webmaster@example.com
|
| 233 |
-
|
| 234 |
-
# SSL Configuration
|
| 235 |
-
SSLEngine on
|
| 236 |
-
SSLCertificateFile /path/to/certificate.crt
|
| 237 |
-
SSLCertificateKeyFile /path/to/private.key
|
| 238 |
-
SSLCertificateChainFile /path/to/chain.crt
|
| 239 |
-
|
| 240 |
-
# Proxy Configuration
|
| 241 |
-
ProxyPreserveHost On
|
| 242 |
-
ProxyPass / http://127.0.0.1:50080/
|
| 243 |
-
ProxyPassReverse / http://127.0.0.1:50080/
|
| 244 |
-
|
| 245 |
-
# WebSocket Support (Required for real-time features)
|
| 246 |
-
RewriteEngine On
|
| 247 |
-
RewriteCond %{HTTP:Upgrade} websocket [NC]
|
| 248 |
-
RewriteCond %{HTTP:Connection} upgrade [NC]
|
| 249 |
-
RewriteRule ^/?(.*) ws://127.0.0.1:50080/$1 [P,L]
|
| 250 |
-
|
| 251 |
-
# Logging
|
| 252 |
-
ErrorLog ${APACHE_LOG_DIR}/a0-instance.error.log
|
| 253 |
-
CustomLog ${APACHE_LOG_DIR}/a0-instance.access.log combined
|
| 254 |
-
</VirtualHost>
|
| 255 |
-
```
|
| 256 |
-
|
| 257 |
-
Enable and restart:
|
| 258 |
-
|
| 259 |
-
```bash
|
| 260 |
-
a2ensite a0-instance.conf
|
| 261 |
-
apache2ctl configtest
|
| 262 |
-
systemctl reload apache2
|
| 263 |
-
```
|
| 264 |
-
|
| 265 |
-
### Configuration for DirectAdmin Apache (AlmaLinux/CentOS)
|
| 266 |
-
|
| 267 |
-
#### Option A: Use httpd-includes.conf (Recommended)
|
| 268 |
-
|
| 269 |
-
Edit `/etc/httpd/conf/extra/httpd-includes.conf`:
|
| 270 |
-
|
| 271 |
-
```apache
|
| 272 |
-
# Agent Zero Proxy Configuration
|
| 273 |
-
# Instance: a0-instance
|
| 274 |
-
# Domain: a0.example.com
|
| 275 |
-
# Note: Use specific IP, not wildcards, for DirectAdmin compatibility
|
| 276 |
-
|
| 277 |
-
<VirtualHost YOUR_SERVER_IP:80>
|
| 278 |
-
ServerName a0.example.com
|
| 279 |
-
ServerAlias www.a0.example.com
|
| 280 |
-
|
| 281 |
-
RewriteEngine On
|
| 282 |
-
RewriteCond %{HTTPS} off
|
| 283 |
-
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
|
| 284 |
-
</VirtualHost>
|
| 285 |
-
|
| 286 |
-
<VirtualHost YOUR_SERVER_IP:443>
|
| 287 |
-
ServerName a0.example.com
|
| 288 |
-
ServerAlias www.a0.example.com
|
| 289 |
-
ServerAdmin webmaster@example.com
|
| 290 |
-
|
| 291 |
-
SSLEngine on
|
| 292 |
-
# DirectAdmin SSL cert paths (adjust user and domain)
|
| 293 |
-
SSLCertificateFile /usr/local/directadmin/data/users/USERNAME/domains/example.com.cert.combined
|
| 294 |
-
SSLCertificateKeyFile /usr/local/directadmin/data/users/USERNAME/domains/example.com.key
|
| 295 |
-
|
| 296 |
-
ProxyPreserveHost On
|
| 297 |
-
ProxyPass / http://127.0.0.1:50080/
|
| 298 |
-
ProxyPassReverse / http://127.0.0.1:50080/
|
| 299 |
-
|
| 300 |
-
# WebSocket Support
|
| 301 |
-
RewriteEngine On
|
| 302 |
-
RewriteCond %{HTTP:Upgrade} websocket [NC]
|
| 303 |
-
RewriteCond %{HTTP:Connection} upgrade [NC]
|
| 304 |
-
RewriteRule ^/?(.*) ws://127.0.0.1:50080/$1 [P,L]
|
| 305 |
-
|
| 306 |
-
ErrorLog /var/log/httpd/domains/a0.example.com.error.log
|
| 307 |
-
CustomLog /var/log/httpd/domains/a0.example.com.access.log combined
|
| 308 |
-
</VirtualHost>
|
| 309 |
-
```
|
| 310 |
-
|
| 311 |
-
> ⚠️ **Important for DirectAdmin:**
|
| 312 |
-
> - Use **specific IP address** (e.g., `192.168.1.100:443`), not `*:443`
|
| 313 |
-
> - IP-bound vhosts take precedence over DirectAdmin's vhosts
|
| 314 |
-
> - SSL certs are in `/usr/local/directadmin/data/users/USERNAME/domains/`
|
| 315 |
-
|
| 316 |
-
#### Option B: Standalone conf.d file
|
| 317 |
-
|
| 318 |
-
If `/etc/httpd/conf.d/` is included in your Apache config:
|
| 319 |
-
|
| 320 |
-
```bash
|
| 321 |
-
# Check if conf.d is included
|
| 322 |
-
grep 'conf.d' /etc/httpd/conf/httpd.conf
|
| 323 |
-
|
| 324 |
-
# If not, add before directadmin-vhosts.conf include:
|
| 325 |
-
sed -i '/Include conf\/extra\/directadmin-vhosts.conf/i Include conf.d/*.conf' /etc/httpd/conf/httpd.conf
|
| 326 |
-
|
| 327 |
-
# Create config
|
| 328 |
-
mkdir -p /etc/httpd/conf.d
|
| 329 |
-
cat > /etc/httpd/conf.d/httpd-vhosts-a0.conf << 'EOF'
|
| 330 |
-
# Your vhost config here (same as Option A)
|
| 331 |
-
EOF
|
| 332 |
-
```
|
| 333 |
-
|
| 334 |
-
### Verify and Restart Apache
|
| 335 |
-
|
| 336 |
-
```bash
|
| 337 |
-
# Test configuration
|
| 338 |
-
httpd -t # AlmaLinux/CentOS
|
| 339 |
-
apachectl -t # Alternative
|
| 340 |
-
apache2ctl -t # Debian/Ubuntu
|
| 341 |
-
|
| 342 |
-
# Restart
|
| 343 |
-
systemctl restart httpd # AlmaLinux/CentOS
|
| 344 |
-
systemctl restart apache2 # Debian/Ubuntu
|
| 345 |
-
```
|
| 346 |
-
|
| 347 |
-
---
|
| 348 |
-
|
| 349 |
-
## SSL/TLS Configuration
|
| 350 |
-
|
| 351 |
-
### Option A: Let's Encrypt with Certbot
|
| 352 |
-
|
| 353 |
-
```bash
|
| 354 |
-
# Install Certbot
|
| 355 |
-
# Debian/Ubuntu:
|
| 356 |
-
apt-get install certbot python3-certbot-apache
|
| 357 |
-
|
| 358 |
-
# AlmaLinux/CentOS:
|
| 359 |
-
dnf install certbot python3-certbot-apache
|
| 360 |
-
|
| 361 |
-
# Obtain certificate
|
| 362 |
-
certbot --apache -d a0.example.com -d www.a0.example.com
|
| 363 |
-
|
| 364 |
-
# Auto-renewal (usually automatic, but verify)
|
| 365 |
-
certbot renew --dry-run
|
| 366 |
-
```
|
| 367 |
-
|
| 368 |
-
### Option B: DirectAdmin Auto-SSL
|
| 369 |
-
|
| 370 |
-
If using DirectAdmin, SSL is typically managed automatically:
|
| 371 |
-
|
| 372 |
-
1. Create domain/subdomain in DirectAdmin
|
| 373 |
-
2. Enable "SSL" for the domain
|
| 374 |
-
3. DirectAdmin will obtain Let's Encrypt certificate
|
| 375 |
-
4. Certs stored in `/usr/local/directadmin/data/users/USERNAME/domains/`
|
| 376 |
-
|
| 377 |
-
### Option C: Manual/Commercial Certificates
|
| 378 |
-
|
| 379 |
-
Place certificates in secure location:
|
| 380 |
-
|
| 381 |
-
```bash
|
| 382 |
-
mkdir -p /etc/ssl/a0
|
| 383 |
-
chmod 700 /etc/ssl/a0
|
| 384 |
-
|
| 385 |
-
# Copy your certificates
|
| 386 |
-
cp certificate.crt /etc/ssl/a0/
|
| 387 |
-
cp private.key /etc/ssl/a0/
|
| 388 |
-
cp chain.crt /etc/ssl/a0/ # if applicable
|
| 389 |
-
|
| 390 |
-
chmod 600 /etc/ssl/a0/*
|
| 391 |
-
```
|
| 392 |
-
|
| 393 |
-
---
|
| 394 |
-
|
| 395 |
-
## Authentication Setup
|
| 396 |
-
|
| 397 |
-
### Understanding A0 Authentication Variables
|
| 398 |
-
|
| 399 |
-
| Variable | Purpose | Example |
|
| 400 |
-
|----------|---------|--------|
|
| 401 |
-
| `AUTH_LOGIN` | The **username** for login | `AUTH_LOGIN=admin` |
|
| 402 |
-
| `AUTH_PASSWORD` | The **password** for login | `AUTH_PASSWORD=SecurePass123!` |
|
| 403 |
-
|
| 404 |
-
> ⚠️ **Common Mistake:** `AUTH_LOGIN` is the username, **not** a boolean to enable auth!
|
| 405 |
-
|
| 406 |
-
### Setting Up Authentication
|
| 407 |
-
|
| 408 |
-
```bash
|
| 409 |
-
# Edit .env file
|
| 410 |
-
vi /opt/a0-instance/.env
|
| 411 |
-
|
| 412 |
-
# Add/update these lines:
|
| 413 |
-
AUTH_LOGIN=your_username
|
| 414 |
-
AUTH_PASSWORD=your_secure_password
|
| 415 |
-
|
| 416 |
-
# Restart container to apply
|
| 417 |
-
docker restart a0-instance
|
| 418 |
-
```
|
| 419 |
-
|
| 420 |
-
### Password Requirements
|
| 421 |
-
|
| 422 |
-
- Minimum 8 characters recommended
|
| 423 |
-
- Special characters are supported (properly escaped)
|
| 424 |
-
- Avoid these characters in passwords: `' " \` $ \` (or escape carefully)
|
| 425 |
-
|
| 426 |
-
### Disabling Authentication (Not Recommended)
|
| 427 |
-
|
| 428 |
-
To disable authentication (local/dev use only):
|
| 429 |
-
|
| 430 |
-
```bash
|
| 431 |
-
# Remove or comment out both lines in .env:
|
| 432 |
-
# AUTH_LOGIN=
|
| 433 |
-
# AUTH_PASSWORD=
|
| 434 |
-
|
| 435 |
-
docker restart a0-instance
|
| 436 |
-
```
|
| 437 |
-
|
| 438 |
-
---
|
| 439 |
-
|
| 440 |
-
## Domain & DNS Setup
|
| 441 |
-
|
| 442 |
-
### DNS Configuration
|
| 443 |
-
|
| 444 |
-
Create an A record pointing to your server:
|
| 445 |
-
|
| 446 |
-
| Type | Name | Value | TTL |
|
| 447 |
-
|------|------|-------|-----|
|
| 448 |
-
| A | a0 | YOUR_SERVER_IP | 300 |
|
| 449 |
-
| A | www.a0 | YOUR_SERVER_IP | 300 |
|
| 450 |
-
|
| 451 |
-
### DirectAdmin Subdomain Setup
|
| 452 |
-
|
| 453 |
-
1. Log into DirectAdmin
|
| 454 |
-
2. Navigate to: **Domain Setup** → Select domain → **Subdomain Management**
|
| 455 |
-
3. Create subdomain (e.g., `a0`)
|
| 456 |
-
4. Note: You'll override the DocumentRoot with Apache proxy config
|
| 457 |
-
|
| 458 |
-
### Verify DNS Propagation
|
| 459 |
-
|
| 460 |
-
```bash
|
| 461 |
-
# Check DNS resolution
|
| 462 |
-
dig a0.example.com +short
|
| 463 |
-
nslookup a0.example.com
|
| 464 |
-
|
| 465 |
-
# Should return your server IP
|
| 466 |
-
```
|
| 467 |
-
|
| 468 |
-
---
|
| 469 |
-
|
| 470 |
-
## Verification & Testing
|
| 471 |
-
|
| 472 |
-
### Step-by-Step Verification Checklist
|
| 473 |
-
|
| 474 |
-
```bash
|
| 475 |
-
# 1. Verify Docker container is running
|
| 476 |
-
docker ps | grep a0-instance
|
| 477 |
-
|
| 478 |
-
# 2. Check container logs for errors
|
| 479 |
-
docker logs a0-instance --tail 50
|
| 480 |
-
|
| 481 |
-
# 3. Test local container access
|
| 482 |
-
curl -I http://127.0.0.1:50080/
|
| 483 |
-
# Expected: HTTP/1.1 302 FOUND, Location: /login
|
| 484 |
-
|
| 485 |
-
# 4. Test Apache config
|
| 486 |
-
httpd -t # or apache2ctl -t
|
| 487 |
-
|
| 488 |
-
# 5. Check Apache is proxying correctly
|
| 489 |
-
curl -I http://127.0.0.1:80 -H "Host: a0.example.com"
|
| 490 |
-
curl -Ik https://127.0.0.1:443 -H "Host: a0.example.com"
|
| 491 |
-
|
| 492 |
-
# 6. Test external HTTPS access
|
| 493 |
-
curl -I https://a0.example.com/
|
| 494 |
-
# Expected: HTTP/2 302 with Location: /login
|
| 495 |
-
|
| 496 |
-
# 7. Test login page loads
|
| 497 |
-
curl -s https://a0.example.com/login | grep -i "<title>"
|
| 498 |
-
# Expected: <title>Login - Agent Zero</title>
|
| 499 |
-
```
|
| 500 |
-
|
| 501 |
-
### WebSocket Verification
|
| 502 |
-
|
| 503 |
-
```bash
|
| 504 |
-
# Install wscat if needed
|
| 505 |
-
npm install -g wscat
|
| 506 |
-
|
| 507 |
-
# Test WebSocket connection
|
| 508 |
-
wscat -c wss://a0.example.com/ws
|
| 509 |
-
```
|
| 510 |
-
|
| 511 |
-
---
|
| 512 |
-
|
| 513 |
-
## Troubleshooting
|
| 514 |
-
|
| 515 |
-
### Issue: "Invalid Credentials" on Login
|
| 516 |
-
|
| 517 |
-
**Cause:** Incorrect `.env` configuration
|
| 518 |
-
|
| 519 |
-
**Fix:**
|
| 520 |
-
```bash
|
| 521 |
-
# Verify .env inside container
|
| 522 |
-
docker exec a0-instance cat /a0/.env
|
| 523 |
-
|
| 524 |
-
# Ensure format is:
|
| 525 |
-
# AUTH_LOGIN=username (NOT AUTH_LOGIN=true)
|
| 526 |
-
# AUTH_PASSWORD=password
|
| 527 |
-
|
| 528 |
-
# Restart after fixing
|
| 529 |
-
docker restart a0-instance
|
| 530 |
-
```
|
| 531 |
-
|
| 532 |
-
### Issue: 403 Forbidden
|
| 533 |
-
|
| 534 |
-
**Cause:** DirectAdmin vhost overriding custom proxy config
|
| 535 |
-
|
| 536 |
-
**Fix:**
|
| 537 |
-
```bash
|
| 538 |
-
# Check vhost order
|
| 539 |
-
httpd -S 2>&1 | grep your-domain
|
| 540 |
-
|
| 541 |
-
# Ensure custom config loads BEFORE directadmin-vhosts.conf
|
| 542 |
-
# Use specific IP binding (e.g., 192.168.1.1:443) not wildcards (*:443)
|
| 543 |
-
|
| 544 |
-
# Restart Apache
|
| 545 |
-
systemctl restart httpd
|
| 546 |
-
```
|
| 547 |
-
|
| 548 |
-
### Issue: 502 Bad Gateway
|
| 549 |
-
|
| 550 |
-
**Cause:** Container not running or wrong port
|
| 551 |
-
|
| 552 |
-
**Fix:**
|
| 553 |
-
```bash
|
| 554 |
-
# Check container status
|
| 555 |
-
docker ps -a | grep a0-instance
|
| 556 |
-
|
| 557 |
-
# If stopped, check logs
|
| 558 |
-
docker logs a0-instance
|
| 559 |
-
|
| 560 |
-
# Restart container
|
| 561 |
-
docker start a0-instance
|
| 562 |
-
|
| 563 |
-
# Verify port binding
|
| 564 |
-
netstat -tlnp | grep 50080
|
| 565 |
-
```
|
| 566 |
-
|
| 567 |
-
### Issue: 504 Gateway Timeout
|
| 568 |
-
|
| 569 |
-
**Cause:** Container overloaded or unresponsive
|
| 570 |
-
|
| 571 |
-
**Fix:**
|
| 572 |
-
```bash
|
| 573 |
-
# Check container resource usage
|
| 574 |
-
docker stats a0-instance --no-stream
|
| 575 |
-
|
| 576 |
-
# Restart container
|
| 577 |
-
docker restart a0-instance
|
| 578 |
-
|
| 579 |
-
# Check for memory issues
|
| 580 |
-
free -h
|
| 581 |
-
```
|
| 582 |
-
|
| 583 |
-
### Issue: WebSocket Connection Failed
|
| 584 |
-
|
| 585 |
-
**Cause:** Missing WebSocket proxy rules
|
| 586 |
-
|
| 587 |
-
**Fix:**
|
| 588 |
-
Ensure these lines are in your vhost config:
|
| 589 |
-
|
| 590 |
-
```apache
|
| 591 |
-
RewriteEngine On
|
| 592 |
-
RewriteCond %{HTTP:Upgrade} websocket [NC]
|
| 593 |
-
RewriteCond %{HTTP:Connection} upgrade [NC]
|
| 594 |
-
RewriteRule ^/?(.*) ws://127.0.0.1:50080/$1 [P,L]
|
| 595 |
-
```
|
| 596 |
-
|
| 597 |
-
### Issue: Container Won't Start
|
| 598 |
-
|
| 599 |
-
**Cause:** Port conflict or Docker issue
|
| 600 |
-
|
| 601 |
-
**Fix:**
|
| 602 |
-
```bash
|
| 603 |
-
# Check what's using the port
|
| 604 |
-
netstat -tlnp | grep 50080
|
| 605 |
-
|
| 606 |
-
# Remove conflicting container
|
| 607 |
-
docker rm -f conflicting-container
|
| 608 |
-
|
| 609 |
-
# Check Docker daemon
|
| 610 |
-
systemctl status docker
|
| 611 |
-
journalctl -u docker --since "1 hour ago"
|
| 612 |
-
```
|
| 613 |
-
|
| 614 |
-
### Issue: Changes to .env Not Taking Effect
|
| 615 |
-
|
| 616 |
-
**Cause:** Container needs restart to reload env
|
| 617 |
-
|
| 618 |
-
**Fix:**
|
| 619 |
-
```bash
|
| 620 |
-
docker restart a0-instance
|
| 621 |
-
|
| 622 |
-
# Verify env is loaded
|
| 623 |
-
docker exec a0-instance cat /a0/.env
|
| 624 |
-
```
|
| 625 |
-
|
| 626 |
-
---
|
| 627 |
-
|
| 628 |
-
## Maintenance & Updates
|
| 629 |
-
|
| 630 |
-
### Updating Agent Zero
|
| 631 |
-
|
| 632 |
-
```bash
|
| 633 |
-
# Pull latest image
|
| 634 |
-
docker pull agent0ai/agent-zero:latest
|
| 635 |
-
|
| 636 |
-
# Stop and remove old container (data persists in volumes)
|
| 637 |
-
docker stop a0-instance
|
| 638 |
-
docker rm a0-instance
|
| 639 |
-
|
| 640 |
-
# Recreate with same settings
|
| 641 |
-
docker run -d --name a0-instance --restart unless-stopped -p 50080:80 -v /opt/a0-instance/.env:/a0/.env -v /opt/a0-instance/usr:/a0/usr -v /opt/agent-zero:latest
|
| 642 |
-
```
|
| 643 |
-
|
| 644 |
-
### Backup Strategy
|
| 645 |
-
|
| 646 |
-
```bash
|
| 647 |
-
# Backup all instance data
|
| 648 |
-
tar -czvf a0-backup-$(date +%Y%m%d).tar.gz /opt/a0-instance/
|
| 649 |
-
|
| 650 |
-
# Key items to backup:
|
| 651 |
-
# - /opt/a0-instance/.env (configuration)
|
| 652 |
-
# - /opt/a0-instance/memory/ (agent memories)
|
| 653 |
-
# - /opt/a0-instance/work_dir/ (working files)
|
| 654 |
-
```
|
| 655 |
-
|
| 656 |
-
### Monitoring
|
| 657 |
-
|
| 658 |
-
```bash
|
| 659 |
-
# Check container health
|
| 660 |
-
docker ps --format "table {{.Names}} {{.Status}} {{.Ports}}"
|
| 661 |
-
|
| 662 |
-
# View recent logs
|
| 663 |
-
docker logs --tail 100 -f a0-instance
|
| 664 |
-
|
| 665 |
-
# Resource usage
|
| 666 |
-
docker stats a0-instance
|
| 667 |
-
```
|
| 668 |
-
|
| 669 |
-
### Docker Cleanup
|
| 670 |
-
|
| 671 |
-
```bash
|
| 672 |
-
# Remove unused images
|
| 673 |
-
docker image prune -f
|
| 674 |
-
|
| 675 |
-
# Remove all unused Docker resources
|
| 676 |
-
docker system prune -f
|
| 677 |
-
```
|
| 678 |
-
|
| 679 |
-
---
|
| 680 |
-
|
| 681 |
-
## Quick Reference
|
| 682 |
-
|
| 683 |
-
### Essential Commands
|
| 684 |
-
|
| 685 |
-
```bash
|
| 686 |
-
# Container Management
|
| 687 |
-
docker start a0-instance
|
| 688 |
-
docker stop a0-instance
|
| 689 |
-
docker restart a0-instance
|
| 690 |
-
docker logs a0-instance
|
| 691 |
-
docker exec -it a0-instance bash
|
| 692 |
-
|
| 693 |
-
# Apache Management
|
| 694 |
-
systemctl restart httpd # RHEL/AlmaLinux
|
| 695 |
-
systemctl restart apache2 # Debian/Ubuntu
|
| 696 |
-
httpd -t # Test config
|
| 697 |
-
|
| 698 |
-
# Quick Diagnostics
|
| 699 |
-
docker ps | grep a0
|
| 700 |
-
curl -I https://your-domain.com/login
|
| 701 |
-
```
|
| 702 |
-
|
| 703 |
-
### Standard Paths
|
| 704 |
-
|
| 705 |
-
| Component | Path |
|
| 706 |
-
|-----------|----- |
|
| 707 |
-
| Instance Data | `/opt/a0-instance/` |
|
| 708 |
-
| Environment File | `/opt/a0-instance/.env` |
|
| 709 |
-
| Memory Storage | `/opt/a0-instance/memory/` |
|
| 710 |
-
| Work Directory | `/opt/a0-instance/work_dir/` |
|
| 711 |
-
| Apache Config (Standard) | `/etc/apache2/sites-available/` |
|
| 712 |
-
| Apache Config (DirectAdmin) | `/etc/httpd/conf/extra/httpd-includes.conf` |
|
| 713 |
-
| DirectAdmin SSL Certs | `/usr/local/directadmin/data/users/USER/domains/` |
|
| 714 |
-
|
| 715 |
-
### Standard Ports
|
| 716 |
-
|
| 717 |
-
| Port | Purpose |
|
| 718 |
-
|------|---------|
|
| 719 |
-
| 50080 | First A0 instance |
|
| 720 |
-
| 50081 | Second A0 instance |
|
| 721 |
-
| 50082 | Third A0 instance |
|
| 722 |
-
| 80 | HTTP (redirect to HTTPS) |
|
| 723 |
-
| 443 | HTTPS (main access) |
|
| 724 |
-
|
| 725 |
-
### .env Template
|
| 726 |
-
|
| 727 |
-
```bash
|
| 728 |
-
# Agent Zero Configuration Template
|
| 729 |
-
# Copy and customize for each instance
|
| 730 |
-
|
| 731 |
-
# Authentication (REQUIRED for production)
|
| 732 |
-
AUTH_LOGIN=your_username
|
| 733 |
-
AUTH_PASSWORD=your_secure_password
|
| 734 |
-
|
| 735 |
-
# Optional: Additional settings
|
| 736 |
-
# Refer to Agent Zero documentation for all options
|
| 737 |
-
```
|
| 738 |
-
|
| 739 |
-
---
|
| 740 |
-
|
| 741 |
-
## Appendix: Multi-Instance Setup
|
| 742 |
-
|
| 743 |
-
For running multiple A0 instances on the same server:
|
| 744 |
-
|
| 745 |
-
```bash
|
| 746 |
-
# Instance 1: a0-primary on port 50080
|
| 747 |
-
mkdir -p /opt/a0-primary
|
| 748 |
-
# ... create .env, run container on port 50080
|
| 749 |
-
|
| 750 |
-
# Instance 2: a0-dev on port 50081
|
| 751 |
-
mkdir -p /opt/a0-dev
|
| 752 |
-
# ... create .env, run container on port 50081
|
| 753 |
-
|
| 754 |
-
# Instance 3: a0-backup on port 50082
|
| 755 |
-
mkdir -p /opt/a0-backup
|
| 756 |
-
# ... create .env, run container on port 50082
|
| 757 |
-
```
|
| 758 |
-
|
| 759 |
-
Each instance needs:
|
| 760 |
-
- Unique container name
|
| 761 |
-
- Unique host port
|
| 762 |
-
- Separate data directory
|
| 763 |
-
- Separate domain/subdomain
|
| 764 |
-
- Separate Apache vhost config
|
| 765 |
-
|
| 766 |
-
---
|
| 767 |
-
|
| 768 |
-
*This guide comes from successful Agent Zero deployments across DirectAdmin and standard Linux environments.*
|
| 769 |
-
|
| 770 |
-
Contributed by @hurtdidit in the A0 Community.
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:35d128f65e9196f4a7714c2eca191b2a2535049356ad8c7e9a30c60d021068b1
|
| 3 |
+
size 18115
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
extensions/AGENTS.md
CHANGED
|
@@ -1,39 +1,3 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
- Own core lifecycle extension implementations for backend and WebUI extension points.
|
| 6 |
-
- Keep built-in hook behavior ordered, discoverable, and compatible with plugin extension discovery.
|
| 7 |
-
|
| 8 |
-
## Ownership
|
| 9 |
-
|
| 10 |
-
- `python/` contains backend lifecycle hooks executed through `helpers.extension`.
|
| 11 |
-
- `webui/` contains frontend extension contributions loaded through `webui/js/extensions.js`.
|
| 12 |
-
- Plugin-specific extensions belong inside each plugin's `extensions/` directory.
|
| 13 |
-
|
| 14 |
-
## Local Contracts
|
| 15 |
-
|
| 16 |
-
- Extension directory names are runtime extension point names.
|
| 17 |
-
- File ordering matters when names include numeric prefixes.
|
| 18 |
-
- Extensions must be safe to run repeatedly when the lifecycle point can fire multiple times.
|
| 19 |
-
- Secret masking, auth, security, and persistence extensions must not be bypassed by convenience changes.
|
| 20 |
-
|
| 21 |
-
## Work Guidance
|
| 22 |
-
|
| 23 |
-
- Keep extension code small and focused on its hook point.
|
| 24 |
-
- Move shared logic into `helpers/` when it is reused outside one extension.
|
| 25 |
-
- Coordinate changes with plugin extension docs and tests when extension point semantics change.
|
| 26 |
-
|
| 27 |
-
## Verification
|
| 28 |
-
|
| 29 |
-
- Run targeted lifecycle, prompt, stream, WebSocket, or WebUI extension tests for changed hook points.
|
| 30 |
-
- Smoke-test startup when changing initialization, migration, or system-prompt extensions.
|
| 31 |
-
|
| 32 |
-
## Child DOX Index
|
| 33 |
-
|
| 34 |
-
Direct child DOX files:
|
| 35 |
-
|
| 36 |
-
| Child | Scope |
|
| 37 |
-
| --- | --- |
|
| 38 |
-
| [python/AGENTS.md](python/AGENTS.md) | Backend lifecycle extension hook files. |
|
| 39 |
-
| [webui/AGENTS.md](webui/AGENTS.md) | Frontend extension contributions. |
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:2fee5d7084cc2d56ea3b981a3c921e2e7944bc20a20fd8691d5caf0b94b2d7f8
|
| 3 |
+
size 1537
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
extensions/python/AGENTS.md
CHANGED
|
@@ -1,68 +1,3 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
- Own built-in backend lifecycle extensions under `extensions/python/`.
|
| 6 |
-
- Keep Python hook behavior compatible with `helpers.extension.call_extensions_async` and `call_extensions_sync`.
|
| 7 |
-
|
| 8 |
-
## Ownership
|
| 9 |
-
|
| 10 |
-
- Each direct subdirectory is one named extension point.
|
| 11 |
-
- Python files inside an extension point are loaded in deterministic filename order.
|
| 12 |
-
- Implicit `@extensible` hook implementations use `_functions/<module>/<qualname>/<start|end>/` layout when present.
|
| 13 |
-
|
| 14 |
-
## Local Contracts
|
| 15 |
-
|
| 16 |
-
- Extension functions must match the arguments supplied by their hook point.
|
| 17 |
-
- Preserve numeric prefixes when ordering affects prompt construction, stream masking, persistence, or cleanup.
|
| 18 |
-
- Use `AgentContext` from `agent` when context access is needed.
|
| 19 |
-
- Do not log unmasked secrets, raw hidden prompt sections, or private user data.
|
| 20 |
-
|
| 21 |
-
## Work Guidance
|
| 22 |
-
|
| 23 |
-
- Keep extension modules import-light; many hooks run during hot paths.
|
| 24 |
-
- Use mutable `ctx` or `data` dictionaries according to the hook contract when rewriting content.
|
| 25 |
-
- Add or update tests when a hook changes prompt content, message history, tool output, streaming, or persistence behavior.
|
| 26 |
-
|
| 27 |
-
## Verification
|
| 28 |
-
|
| 29 |
-
- Run targeted tests for the affected lifecycle area.
|
| 30 |
-
- Run a startup smoke check for `agent_init`, `startup_migration`, or `system_prompt` changes when practical.
|
| 31 |
-
|
| 32 |
-
## Child DOX Index
|
| 33 |
-
|
| 34 |
-
Direct child DOX files:
|
| 35 |
-
|
| 36 |
-
| Child | Scope |
|
| 37 |
-
| --- | --- |
|
| 38 |
-
| [_functions/AGENTS.md](_functions/AGENTS.md) | Implicit `@extensible` backend hook implementations. |
|
| 39 |
-
| [agent_init/AGENTS.md](agent_init/AGENTS.md) | Agent context initialization hooks. |
|
| 40 |
-
| [banners/AGENTS.md](banners/AGENTS.md) | Backend banner and discovery-card contributions. |
|
| 41 |
-
| [before_main_llm_call/AGENTS.md](before_main_llm_call/AGENTS.md) | Pre-main-model-call behavior. |
|
| 42 |
-
| [error_format/AGENTS.md](error_format/AGENTS.md) | Error formatting and masking behavior. |
|
| 43 |
-
| [hist_add_before/AGENTS.md](hist_add_before/AGENTS.md) | Pre-history-insertion masking behavior. |
|
| 44 |
-
| [hist_add_tool_result/AGENTS.md](hist_add_tool_result/AGENTS.md) | Tool-result history side effects. |
|
| 45 |
-
| [job_loop/AGENTS.md](job_loop/AGENTS.md) | Periodic backend maintenance jobs. |
|
| 46 |
-
| [message_loop_end/AGENTS.md](message_loop_end/AGENTS.md) | End-of-message-loop history and persistence behavior. |
|
| 47 |
-
| [message_loop_result/AGENTS.md](message_loop_result/AGENTS.md) | Completed model-result normalization and default-processing interception. |
|
| 48 |
-
| [message_loop_prompts_after/AGENTS.md](message_loop_prompts_after/AGENTS.md) | Prompt protocol and extras assembled around message-loop prompt construction. |
|
| 49 |
-
| [message_loop_prompts_before/AGENTS.md](message_loop_prompts_before/AGENTS.md) | Pre-prompt-construction message-loop gates. |
|
| 50 |
-
| [message_loop_start/AGENTS.md](message_loop_start/AGENTS.md) | Start-of-message-loop iteration state. |
|
| 51 |
-
| [monologue_end/AGENTS.md](monologue_end/AGENTS.md) | End-of-monologue UI and cleanup behavior. |
|
| 52 |
-
| [monologue_start/AGENTS.md](monologue_start/AGENTS.md) | Core start-of-monologue lifecycle extensions. |
|
| 53 |
-
| [process_chain_end/AGENTS.md](process_chain_end/AGENTS.md) | Process-chain completion and queued-message handling. |
|
| 54 |
-
| [reasoning_stream/AGENTS.md](reasoning_stream/AGENTS.md) | Full reasoning stream handling. |
|
| 55 |
-
| [reasoning_stream_chunk/AGENTS.md](reasoning_stream_chunk/AGENTS.md) | Reasoning stream chunk masking. |
|
| 56 |
-
| [reasoning_stream_end/AGENTS.md](reasoning_stream_end/AGENTS.md) | Reasoning stream finalization. |
|
| 57 |
-
| [response_stream/AGENTS.md](response_stream/AGENTS.md) | Full assistant response stream handling. |
|
| 58 |
-
| [response_stream_chunk/AGENTS.md](response_stream_chunk/AGENTS.md) | Assistant response chunk masking. |
|
| 59 |
-
| [response_stream_end/AGENTS.md](response_stream_end/AGENTS.md) | Assistant response stream finalization. |
|
| 60 |
-
| [startup_migration/AGENTS.md](startup_migration/AGENTS.md) | Startup migrations. |
|
| 61 |
-
| [system_prompt/AGENTS.md](system_prompt/AGENTS.md) | Core system prompt section construction. |
|
| 62 |
-
| [tool_execute_after/AGENTS.md](tool_execute_after/AGENTS.md) | Post-tool-execution processing. |
|
| 63 |
-
| [tool_execute_before/AGENTS.md](tool_execute_before/AGENTS.md) | Pre-tool-execution processing. |
|
| 64 |
-
| [user_message_ui/AGENTS.md](user_message_ui/AGENTS.md) | User-visible UI message hooks. |
|
| 65 |
-
| [util_model_call_before/AGENTS.md](util_model_call_before/AGENTS.md) | Pre-utility-model-call masking. |
|
| 66 |
-
| [webui_ws_connect/AGENTS.md](webui_ws_connect/AGENTS.md) | WebUI WebSocket connect behavior. |
|
| 67 |
-
| [webui_ws_disconnect/AGENTS.md](webui_ws_disconnect/AGENTS.md) | WebUI WebSocket disconnect behavior. |
|
| 68 |
-
| [webui_ws_event/AGENTS.md](webui_ws_event/AGENTS.md) | Incoming WebUI WebSocket event behavior. |
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:a60e8fc1128128aafbb5a9a5b45033ab0d21af713353e168f3008c2276b71cac
|
| 3 |
+
size 4681
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
extensions/python/_functions/AGENTS.md
CHANGED
|
@@ -1,33 +1,3 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
- Own implicit `@extensible` backend hook implementations.
|
| 6 |
-
- Preserve nested module, class/function, method, and `start`/`end` extension layout.
|
| 7 |
-
|
| 8 |
-
## Ownership
|
| 9 |
-
|
| 10 |
-
- Each nested path mirrors a Python module and qualname segment.
|
| 11 |
-
- Leaf `start/` and `end/` directories own ordered extension files for that extensible function point.
|
| 12 |
-
|
| 13 |
-
## Local Contracts
|
| 14 |
-
|
| 15 |
-
- Do not flatten nested qualname paths into retired legacy folder names.
|
| 16 |
-
- Extension functions must match the implicit hook's supplied arguments.
|
| 17 |
-
- Preserve ordering prefixes where exception handling, watchdog registration, or cleanup depends on them.
|
| 18 |
-
- Hooks that mirror persisted AI responses into UI logs must reuse existing stream log items and avoid duplicating live response-tool logs.
|
| 19 |
-
- The `AgentContext.run_task/end` hook attaches integration callbacks to the returned `DeferredTask`; keep terminal side effects out of `agent.py`.
|
| 20 |
-
- Recovery-loop circuit breakers must stop at the General Settings limit and render their user-visible cost warning from a core framework prompt.
|
| 21 |
-
- Prompt settings snapshots must be task-local, accessed through `get_settings_for_prompt()`, and end with the matching `Agent.prepare_prompt` call, including exceptional exits.
|
| 22 |
-
|
| 23 |
-
## Work Guidance
|
| 24 |
-
|
| 25 |
-
- Keep implicit hook extensions narrow and colocated with the exact function point they extend.
|
| 26 |
-
|
| 27 |
-
## Verification
|
| 28 |
-
|
| 29 |
-
- Run targeted tests for the affected function point after changes.
|
| 30 |
-
|
| 31 |
-
## Child DOX Index
|
| 32 |
-
|
| 33 |
-
No child DOX files.
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:45b0d49727663cfd9f6c3bf81431bde197789b2392924aa68bed1a8afae2c296
|
| 3 |
+
size 1501
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
extensions/python/_functions/__main__/init_a0/end/_10_register_watchdogs.py
CHANGED
|
@@ -1,11 +1,3 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
class RegisterWatchDogs(Extension):
|
| 5 |
-
|
| 6 |
-
def execute(self, **kwargs):
|
| 7 |
-
from helpers.plugins import register_watchdogs as register_plugins_watchdogs
|
| 8 |
-
from helpers.api import register_watchdogs as register_api_watchdogs
|
| 9 |
-
|
| 10 |
-
register_plugins_watchdogs()
|
| 11 |
-
register_api_watchdogs()
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:3585ef1b3cd71ea587ba5fed1ebdc4e37be8e6517bc888d4744938bc27561cdd
|
| 3 |
+
size 344
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
extensions/python/_functions/agent/Agent/handle_exception/end/_40_handle_intervention_exception.py
CHANGED
|
@@ -1,21 +1,3 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
from helpers.localization import Localization
|
| 5 |
-
from helpers.errors import InterventionException
|
| 6 |
-
from helpers import errors
|
| 7 |
-
from helpers.print_style import PrintStyle
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
class HandleInterventionException(Extension):
|
| 11 |
-
async def execute(self, data: dict = {}, **kwargs):
|
| 12 |
-
if not self.agent:
|
| 13 |
-
return
|
| 14 |
-
|
| 15 |
-
if not data.get("exception"):
|
| 16 |
-
return
|
| 17 |
-
|
| 18 |
-
if isinstance(data["exception"], InterventionException):
|
| 19 |
-
data["exception"] = None # skip the exception and continue message loop
|
| 20 |
-
|
| 21 |
-
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:04ee5f0807d0d8f697979f33c0ff2ba7049a85bbad3aa6955738a3a60b0336f9
|
| 3 |
+
size 640
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
extensions/python/_functions/agent/Agent/handle_exception/end/_50_handle_repairable_exception.py
CHANGED
|
@@ -1,25 +1,3 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
from helpers.localization import Localization
|
| 5 |
-
from helpers.errors import RepairableException
|
| 6 |
-
from helpers import errors, extension
|
| 7 |
-
from helpers.print_style import PrintStyle
|
| 8 |
-
|
| 9 |
-
class HandleRepairableException(Extension):
|
| 10 |
-
async def execute(self, data: dict = {}, **kwargs):
|
| 11 |
-
if not self.agent:
|
| 12 |
-
return
|
| 13 |
-
|
| 14 |
-
if not data.get("exception"):
|
| 15 |
-
return
|
| 16 |
-
|
| 17 |
-
if isinstance(data["exception"], RepairableException):
|
| 18 |
-
msg = {"message": errors.format_error(data["exception"])}
|
| 19 |
-
await extension.call_extensions_async("error_format", agent=self.agent, msg=msg)
|
| 20 |
-
wmsg = self.agent.hist_add_warning(msg["message"])
|
| 21 |
-
PrintStyle(font_color="red", padding=True).print(msg["message"])
|
| 22 |
-
self.agent.context.log.log(type="warning", content=msg["message"], id=wmsg.id)
|
| 23 |
-
data["exception"] = None
|
| 24 |
-
|
| 25 |
-
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:67e15a2835ee4e4d02f7f277a32a42273f6bddad4e8b2448f3588aec2bcc54b0
|
| 3 |
+
size 991
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
extensions/python/_functions/agent/Agent/handle_exception/end/_90_handle_critical_exception.py
CHANGED
|
@@ -1,43 +1,3 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
from helpers.print_style import PrintStyle
|
| 5 |
-
from helpers import errors
|
| 6 |
-
|
| 7 |
-
from helpers.errors import HandledException
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
class HandleCriticalException(Extension):
|
| 11 |
-
async def execute(self, data: dict = {}, **kwargs):
|
| 12 |
-
if not self.agent:
|
| 13 |
-
return
|
| 14 |
-
|
| 15 |
-
if not (exception:= data.get("exception")):
|
| 16 |
-
return
|
| 17 |
-
|
| 18 |
-
# when exception is HandledException, keep it active, no logging here
|
| 19 |
-
if isinstance(exception, HandledException):
|
| 20 |
-
return
|
| 21 |
-
|
| 22 |
-
# asyncio cancel - chat is being terminated, print out and re-raise as handledException
|
| 23 |
-
if isinstance(exception, asyncio.CancelledError):
|
| 24 |
-
PrintStyle(font_color="white", background_color="red", padding=True).print(
|
| 25 |
-
f"Context {self.agent.context.id} terminated during message loop"
|
| 26 |
-
)
|
| 27 |
-
data["exception"] = HandledException(exception)
|
| 28 |
-
return
|
| 29 |
-
|
| 30 |
-
# other exceptions should be logged and re-raised as HandledException
|
| 31 |
-
error_text = errors.error_text(exception)
|
| 32 |
-
error_message = errors.format_error(exception)
|
| 33 |
-
|
| 34 |
-
PrintStyle(font_color="red", padding=True).print(error_message)
|
| 35 |
-
self.agent.context.log.log(
|
| 36 |
-
type="error",
|
| 37 |
-
content=error_message,
|
| 38 |
-
)
|
| 39 |
-
PrintStyle(font_color="red", padding=True).print(
|
| 40 |
-
f"{self.agent.agent_name}: {error_text}"
|
| 41 |
-
)
|
| 42 |
-
|
| 43 |
-
data["exception"] = HandledException(exception)
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:762c8469756a147e96d7cbed07cb0d585d296006b10475f7fbe143e6ded43b32
|
| 3 |
+
size 1500
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
extensions/python/_functions/agent/Agent/hist_add_ai_response/end/_10_log_plain_responses.py
CHANGED
|
@@ -1,47 +1,3 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
from helpers.extension import Extension
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
class LogPlainResponses(Extension):
|
| 8 |
-
def execute(self, data: dict[str, Any] | None = None, **kwargs):
|
| 9 |
-
if not self.agent or not isinstance(data, dict):
|
| 10 |
-
return
|
| 11 |
-
|
| 12 |
-
call_kwargs = data.get("kwargs")
|
| 13 |
-
if not isinstance(call_kwargs, dict):
|
| 14 |
-
call_kwargs = {}
|
| 15 |
-
|
| 16 |
-
llm_result = call_kwargs.get("llm_result")
|
| 17 |
-
if getattr(llm_result, "mode", "") != "responses":
|
| 18 |
-
return
|
| 19 |
-
|
| 20 |
-
message = call_kwargs.get("message")
|
| 21 |
-
call_args = data.get("args")
|
| 22 |
-
if message is None and isinstance(call_args, tuple) and len(call_args) > 1:
|
| 23 |
-
message = call_args[1]
|
| 24 |
-
if not isinstance(message, str) or not message:
|
| 25 |
-
return
|
| 26 |
-
if (
|
| 27 |
-
extract_tools.extract_tool_request(message) is not None
|
| 28 |
-
or extract_tools.is_misformatted_tool_request(message)
|
| 29 |
-
):
|
| 30 |
-
return
|
| 31 |
-
|
| 32 |
-
params = getattr(getattr(self.agent, "loop_data", None), "params_temporary", None)
|
| 33 |
-
if not isinstance(params, dict) or "log_item_response" in params:
|
| 34 |
-
return
|
| 35 |
-
|
| 36 |
-
log_item = params.get("log_item_generating")
|
| 37 |
-
if log_item is None:
|
| 38 |
-
return
|
| 39 |
-
|
| 40 |
-
params["log_item_response"] = log_item
|
| 41 |
-
log_item.update(
|
| 42 |
-
type="response",
|
| 43 |
-
heading="",
|
| 44 |
-
content=message,
|
| 45 |
-
finished=True,
|
| 46 |
-
update_progress="none",
|
| 47 |
-
)
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:cbb24ea2ec8c6acf3f4a7df4b6042464e4c3471118f865a843ca2d9f90b90950
|
| 3 |
+
size 1498
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
extensions/python/_functions/agent/Agent/hist_add_warning/end/_90_stop_unusable_response_loop.py
CHANGED
|
@@ -1,56 +1,3 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
STATE_KEY = "_unusable_response_failures"
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
class StopUnusableResponseLoop(Extension):
|
| 10 |
-
def execute(self, data: dict | None = None, **kwargs):
|
| 11 |
-
if not self.agent or not isinstance(data, dict):
|
| 12 |
-
return
|
| 13 |
-
|
| 14 |
-
call_kwargs = data.get("kwargs")
|
| 15 |
-
message = call_kwargs.get("message") if isinstance(call_kwargs, dict) else None
|
| 16 |
-
call_args = data.get("args")
|
| 17 |
-
if message is None and isinstance(call_args, tuple) and len(call_args) > 1:
|
| 18 |
-
message = call_args[1]
|
| 19 |
-
|
| 20 |
-
if not isinstance(message, str):
|
| 21 |
-
return
|
| 22 |
-
if message not in {
|
| 23 |
-
self.agent.read_prompt("fw.msg_misformat.md"),
|
| 24 |
-
self.agent.read_prompt("fw.msg_repeat.md"),
|
| 25 |
-
self.agent.read_prompt("fw.msg_empty_response.md"),
|
| 26 |
-
}:
|
| 27 |
-
return
|
| 28 |
-
|
| 29 |
-
loop_data = getattr(self.agent, "loop_data", None)
|
| 30 |
-
state = getattr(loop_data, "params_persistent", None)
|
| 31 |
-
iteration = getattr(loop_data, "iteration", None)
|
| 32 |
-
if not isinstance(state, dict) or not isinstance(iteration, int):
|
| 33 |
-
return
|
| 34 |
-
|
| 35 |
-
previous = state.get(STATE_KEY, {})
|
| 36 |
-
if not isinstance(previous, dict):
|
| 37 |
-
previous = {}
|
| 38 |
-
previous_iteration = previous.get("iteration")
|
| 39 |
-
if previous_iteration == iteration:
|
| 40 |
-
return
|
| 41 |
-
|
| 42 |
-
count = (
|
| 43 |
-
previous.get("count", 0) + 1
|
| 44 |
-
if previous_iteration == iteration - 1
|
| 45 |
-
else 1
|
| 46 |
-
)
|
| 47 |
-
state[STATE_KEY] = {"iteration": iteration, "count": count}
|
| 48 |
-
limit = get_settings()["max_consecutive_unusable_responses"]
|
| 49 |
-
if count < limit:
|
| 50 |
-
return
|
| 51 |
-
|
| 52 |
-
stop_message = self.agent.read_prompt(
|
| 53 |
-
"fw.msg_unusable_response_limit.md", limit=limit
|
| 54 |
-
)
|
| 55 |
-
self.agent.context.log.log(type="warning", content=stop_message)
|
| 56 |
-
data["exception"] = HandledException(stop_message)
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:7c138b131522d75756865ef2aebc656f12c7d16f0ce5feefc6c733a3916b1b84
|
| 3 |
+
size 2012
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
extensions/python/_functions/agent/Agent/prepare_prompt/end/_00_restore_settings.py
CHANGED
|
@@ -1,12 +1,3 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
_TOKEN_KEY = "_prompt_settings_snapshot_token"
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
class RestorePromptSettings(Extension):
|
| 9 |
-
def execute(self, data: dict | None = None, **kwargs):
|
| 10 |
-
token = data.pop(_TOKEN_KEY, None) if isinstance(data, dict) else None
|
| 11 |
-
if token is not None:
|
| 12 |
-
settings.end_prompt_settings_snapshot(token)
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:02352e6a668d95ed2d72d77c3fe417f4ceea29a3ad7601666059c569d06e48e9
|
| 3 |
+
size 385
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
extensions/python/_functions/agent/Agent/prepare_prompt/start/_99_snapshot_settings.py
CHANGED
|
@@ -1,11 +1,3 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
_TOKEN_KEY = "_prompt_settings_snapshot_token"
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
class SnapshotPromptSettings(Extension):
|
| 9 |
-
def execute(self, data: dict | None = None, **kwargs):
|
| 10 |
-
if isinstance(data, dict):
|
| 11 |
-
data[_TOKEN_KEY] = settings.begin_prompt_settings_snapshot()
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:8f60a19ebaf9a35b14e788a31e3fce5a7285fa9fee1228374f2b25edff31a477
|
| 3 |
+
size 328
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
extensions/python/_functions/agent/AgentContext/run_task/end/_10_mark_state_dirty.py
CHANGED
|
@@ -1,14 +1,3 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
class MarkStateDirty(Extension):
|
| 7 |
-
def execute(self, data: dict | None = None, **kwargs) -> None:
|
| 8 |
-
task = data.get("result") if isinstance(data, dict) else None
|
| 9 |
-
if isinstance(task, DeferredTask):
|
| 10 |
-
task.add_done_callback(
|
| 11 |
-
lambda _future: mark_dirty_all(
|
| 12 |
-
reason="agent.AgentContext.run_task_done",
|
| 13 |
-
)
|
| 14 |
-
)
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:02112c06ff56b8de8ed877895b58c0e0ed8057800e55eccf12a9e128f3878d4c
|
| 3 |
+
size 534
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
extensions/python/agent_init/AGENTS.md
CHANGED
|
@@ -1,26 +1,3 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
- Own backend extensions that run when an agent context initializes.
|
| 6 |
-
|
| 7 |
-
## Ownership
|
| 8 |
-
|
| 9 |
-
- Ordered Python files own initial UI message setup and profile settings load behavior.
|
| 10 |
-
|
| 11 |
-
## Local Contracts
|
| 12 |
-
|
| 13 |
-
- Keep initialization idempotent for contexts that may be restored or reloaded.
|
| 14 |
-
- Preserve ordering between initial message creation and profile settings loading.
|
| 15 |
-
|
| 16 |
-
## Work Guidance
|
| 17 |
-
|
| 18 |
-
- Coordinate changes with profile loading, settings resolution, and startup smoke checks.
|
| 19 |
-
|
| 20 |
-
## Verification
|
| 21 |
-
|
| 22 |
-
- Smoke-test new chat/context initialization after changes.
|
| 23 |
-
|
| 24 |
-
## Child DOX Index
|
| 25 |
-
|
| 26 |
-
No child DOX files.
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:a0d9eb62f086092e47acc26b8d95af4020a180c2639da41a45f31987b76f6401
|
| 3 |
+
size 625
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
extensions/python/agent_init/_10_initial_message.py
CHANGED
|
@@ -1,44 +1,3 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
class InitialMessage(Extension):
|
| 7 |
-
|
| 8 |
-
def execute(self, **kwargs):
|
| 9 |
-
"""
|
| 10 |
-
Add an initial greeting message when first user message is processed.
|
| 11 |
-
Called only once per session via _process_chain method.
|
| 12 |
-
"""
|
| 13 |
-
if not self.agent:
|
| 14 |
-
return
|
| 15 |
-
|
| 16 |
-
# Only add initial message for main agent (A0), not subordinate agents
|
| 17 |
-
if self.agent.number != 0:
|
| 18 |
-
return
|
| 19 |
-
|
| 20 |
-
# If the context already contains log messages, do not add another initial message
|
| 21 |
-
if self.agent.context.log.logs:
|
| 22 |
-
return
|
| 23 |
-
|
| 24 |
-
# Construct the initial message from prompt template
|
| 25 |
-
initial_message = self.agent.read_prompt("fw.initial_message.md")
|
| 26 |
-
|
| 27 |
-
# add initial loop data to agent (for hist_add_ai_response)
|
| 28 |
-
self.agent.loop_data = LoopData(user_message=None)
|
| 29 |
-
|
| 30 |
-
# Add the message to history as an AI response
|
| 31 |
-
msg = self.agent.hist_add_ai_response(initial_message)
|
| 32 |
-
|
| 33 |
-
# json parse the message, get the tool_args text
|
| 34 |
-
initial_message_json = json.loads(initial_message)
|
| 35 |
-
initial_message_text = initial_message_json.get("tool_args", {}).get("text", "Hello! How can I help you?")
|
| 36 |
-
|
| 37 |
-
# Add to log (green bubble) for immediate UI display
|
| 38 |
-
self.agent.context.log.log(
|
| 39 |
-
type="response",
|
| 40 |
-
content=initial_message_text,
|
| 41 |
-
finished=True,
|
| 42 |
-
update_progress="none",
|
| 43 |
-
id=msg.id,
|
| 44 |
-
)
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:a600f43500b56a633d3dd0f8eec64e84fd32bfc6a43b55657652c8dc24ccc7a4
|
| 3 |
+
size 1525
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
extensions/python/agent_init/_15_load_profile_settings.py
CHANGED
|
@@ -1,53 +1,3 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
class LoadProfileSettings(Extension):
|
| 7 |
-
|
| 8 |
-
def execute(self, **kwargs) -> None:
|
| 9 |
-
|
| 10 |
-
if not self.agent or not self.agent.config.profile:
|
| 11 |
-
return
|
| 12 |
-
|
| 13 |
-
config_files = subagents.get_paths(self.agent, "settings.json", include_default=False, include_user=False)
|
| 14 |
-
settings_override = {}
|
| 15 |
-
for settings_path in config_files:
|
| 16 |
-
if files.exists(settings_path):
|
| 17 |
-
try:
|
| 18 |
-
override_settings_str = files.read_file(settings_path)
|
| 19 |
-
override_settings = dirty_json.try_parse(override_settings_str)
|
| 20 |
-
if isinstance(override_settings, dict):
|
| 21 |
-
settings_override.update(override_settings)
|
| 22 |
-
else:
|
| 23 |
-
raise Exception(
|
| 24 |
-
f"Subordinate settings in {settings_path} must be a JSON object."
|
| 25 |
-
)
|
| 26 |
-
except Exception as e:
|
| 27 |
-
self.agent.context.log.log(
|
| 28 |
-
type="error",
|
| 29 |
-
content=(
|
| 30 |
-
f"Error loading subordinate settings from {settings_path} for "
|
| 31 |
-
f"profile '{self.agent.config.profile}': {e}"
|
| 32 |
-
),
|
| 33 |
-
)
|
| 34 |
-
|
| 35 |
-
if settings_override:
|
| 36 |
-
current_config = self.agent.config
|
| 37 |
-
new_config = initialize_agent(override_settings=settings_override)
|
| 38 |
-
|
| 39 |
-
for override_key, config_attr in (
|
| 40 |
-
("agent_profile", "profile"),
|
| 41 |
-
("mcp_servers", "mcp_servers"),
|
| 42 |
-
):
|
| 43 |
-
if override_key not in settings_override:
|
| 44 |
-
setattr(new_config, config_attr, getattr(current_config, config_attr))
|
| 45 |
-
self.agent.config = new_config
|
| 46 |
-
# self.agent.context.log.log(
|
| 47 |
-
# type="info",
|
| 48 |
-
# content=(
|
| 49 |
-
# "Loaded custom settings for agent "
|
| 50 |
-
# f"{self.agent.number} with profile '{self.agent.config.profile}'."
|
| 51 |
-
# ),
|
| 52 |
-
# )
|
| 53 |
-
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:661afc11f43f87eb7afcb2cef1690856bb298bde0e99945739fdc4132722d734
|
| 3 |
+
size 2200
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
extensions/python/banners/AGENTS.md
CHANGED
|
@@ -1,28 +1,3 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
- Own backend banner and discovery-card contributions.
|
| 6 |
-
|
| 7 |
-
## Ownership
|
| 8 |
-
|
| 9 |
-
- Ordered Python files append alert banners or discovery cards to the mutable `banners` list.
|
| 10 |
-
|
| 11 |
-
## Local Contracts
|
| 12 |
-
|
| 13 |
-
- Banner IDs must be unique and stable.
|
| 14 |
-
- Use supported banner/card fields and types only.
|
| 15 |
-
- Banner HTML links that trigger WebUI behavior should use supported structured actions, such as `data-banner-action`, instead of inline JavaScript handlers.
|
| 16 |
-
- Do not expose secrets, local paths, or raw system diagnostics in banner text.
|
| 17 |
-
|
| 18 |
-
## Work Guidance
|
| 19 |
-
|
| 20 |
-
- Gate setup or warning banners on current configuration/status where possible.
|
| 21 |
-
|
| 22 |
-
## Verification
|
| 23 |
-
|
| 24 |
-
- Smoke-test welcome-screen banner rendering, ordering, dismissal, and CTA behavior after changes.
|
| 25 |
-
|
| 26 |
-
## Child DOX Index
|
| 27 |
-
|
| 28 |
-
No child DOX files.
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:9384eec1a33ca8900836671c77730e4c3e7ef573abe31700150c8f7b6e2950ff
|
| 3 |
+
size 808
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
extensions/python/banners/_10_unsecured_connection.py
CHANGED
|
@@ -1,63 +1,3 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
class UnsecuredConnectionCheck(Extension):
|
| 7 |
-
"""Check: non-local without credentials, or credentials over non-HTTPS."""
|
| 8 |
-
|
| 9 |
-
async def execute(self, banners: list = [], frontend_context: dict = {}, **kwargs):
|
| 10 |
-
hostname = frontend_context.get("hostname", "")
|
| 11 |
-
protocol = frontend_context.get("protocol", "")
|
| 12 |
-
|
| 13 |
-
auth_login = dotenv.get_dotenv_value(dotenv.KEY_AUTH_LOGIN, "")
|
| 14 |
-
auth_password = dotenv.get_dotenv_value(dotenv.KEY_AUTH_PASSWORD, "")
|
| 15 |
-
has_credentials = bool(auth_login and auth_login.strip() and auth_password and auth_password.strip())
|
| 16 |
-
|
| 17 |
-
is_local = self._is_localhost(hostname)
|
| 18 |
-
is_https = protocol == "https:"
|
| 19 |
-
|
| 20 |
-
if not is_local and not has_credentials:
|
| 21 |
-
banners.append({
|
| 22 |
-
"id": "unsecured-connection",
|
| 23 |
-
"type": "warning",
|
| 24 |
-
"priority": 80,
|
| 25 |
-
"title": "Unsecured Connection",
|
| 26 |
-
"html": """You are accessing Agent Zero from a non-local address without authentication.
|
| 27 |
-
<a href="#section-auth" data-banner-action="open-modal:settings/settings.html#section-auth">
|
| 28 |
-
Configure credentials</a> in Settings → External Services → Authentication.""",
|
| 29 |
-
"dismissible": True,
|
| 30 |
-
"source": "backend"
|
| 31 |
-
})
|
| 32 |
-
|
| 33 |
-
if has_credentials and not is_local and not is_https:
|
| 34 |
-
banners.append({
|
| 35 |
-
"id": "credentials-unencrypted",
|
| 36 |
-
"type": "warning",
|
| 37 |
-
"priority": 90,
|
| 38 |
-
"title": "Credentials May Be Sent Unencrypted",
|
| 39 |
-
"html": """Your connection is not using HTTPS. Login credentials may be transmitted in plain text.
|
| 40 |
-
Consider using HTTPS or a secure tunnel.""",
|
| 41 |
-
"dismissible": True,
|
| 42 |
-
"source": "backend"
|
| 43 |
-
})
|
| 44 |
-
|
| 45 |
-
def _is_localhost(self, hostname: str) -> bool:
|
| 46 |
-
local_patterns = ["localhost", "127.0.0.1", "::1", "0.0.0.0"]
|
| 47 |
-
|
| 48 |
-
if hostname in local_patterns:
|
| 49 |
-
return True
|
| 50 |
-
|
| 51 |
-
# RFC1918 private ranges
|
| 52 |
-
if re.match(r"^192\.168\.\d{1,3}\.\d{1,3}$", hostname):
|
| 53 |
-
return True
|
| 54 |
-
if re.match(r"^10\.\d{1,3}\.\d{1,3}\.\d{1,3}$", hostname):
|
| 55 |
-
return True
|
| 56 |
-
if re.match(r"^172\.(1[6-9]|2\d|3[01])\.\d{1,3}\.\d{1,3}$", hostname):
|
| 57 |
-
return True
|
| 58 |
-
|
| 59 |
-
# .local domains
|
| 60 |
-
if hostname.endswith(".local"):
|
| 61 |
-
return True
|
| 62 |
-
|
| 63 |
-
return False
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:6a8d4f8ed25d1e17d786ae5ea6b1f1d6d29f2b80bc8cce4d4bb4807c5d56c623
|
| 3 |
+
size 2640
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
extensions/python/banners/_30_system_resources.py
CHANGED
|
@@ -1,151 +1,3 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
class SystemResourcesCheck(Extension):
|
| 7 |
-
async def execute(self, banners: list = [], frontend_context: dict = {}, **kwargs):
|
| 8 |
-
try:
|
| 9 |
-
cpu_percent = psutil.cpu_percent(interval=0.1)
|
| 10 |
-
except Exception:
|
| 11 |
-
cpu_percent = None
|
| 12 |
-
|
| 13 |
-
try:
|
| 14 |
-
cpu_cores = psutil.cpu_count(logical=True)
|
| 15 |
-
except Exception:
|
| 16 |
-
cpu_cores = None
|
| 17 |
-
|
| 18 |
-
load_avg = self._get_load_average()
|
| 19 |
-
|
| 20 |
-
try:
|
| 21 |
-
vm = psutil.virtual_memory()
|
| 22 |
-
ram_percent = vm.percent
|
| 23 |
-
ram_used_gb = (vm.total - vm.available) / (1024 ** 3)
|
| 24 |
-
ram_total_gb = vm.total / (1024 ** 3)
|
| 25 |
-
except Exception:
|
| 26 |
-
ram_percent = None
|
| 27 |
-
|
| 28 |
-
ram_used_gb = None
|
| 29 |
-
ram_total_gb = None
|
| 30 |
-
|
| 31 |
-
disk_percent, disk_used_gb, disk_total_gb, disk_path = self._get_disk_usage()
|
| 32 |
-
|
| 33 |
-
try:
|
| 34 |
-
net = psutil.net_io_counters()
|
| 35 |
-
net_sent = self._format_bytes(net.bytes_sent)
|
| 36 |
-
net_recv = self._format_bytes(net.bytes_recv)
|
| 37 |
-
except Exception:
|
| 38 |
-
net_sent = "N/A"
|
| 39 |
-
net_recv = "N/A"
|
| 40 |
-
|
| 41 |
-
load_value = "N/A"
|
| 42 |
-
if load_avg:
|
| 43 |
-
la1, la5, la15 = load_avg
|
| 44 |
-
load_value = f"{la1:.2f} / {la5:.2f} / {la15:.2f}"
|
| 45 |
-
|
| 46 |
-
if disk_percent is None or disk_used_gb is None or disk_total_gb is None:
|
| 47 |
-
disk_value = "N/A"
|
| 48 |
-
else:
|
| 49 |
-
disk_value = f"{disk_used_gb:.2f}/{disk_total_gb:.2f} GB"
|
| 50 |
-
|
| 51 |
-
if cpu_percent is None:
|
| 52 |
-
cpu_value = "N/A"
|
| 53 |
-
else:
|
| 54 |
-
cores_value = "" if cpu_cores is None else f" ({cpu_cores} cores)"
|
| 55 |
-
cpu_value = f"{cpu_percent:.0f}%{cores_value}"
|
| 56 |
-
|
| 57 |
-
if ram_percent is None or ram_used_gb is None or ram_total_gb is None:
|
| 58 |
-
ram_value = "N/A"
|
| 59 |
-
else:
|
| 60 |
-
ram_value = f"{ram_used_gb:.2f}/{ram_total_gb:.2f} GB"
|
| 61 |
-
|
| 62 |
-
cpu_bar = self._bar_html(cpu_percent)
|
| 63 |
-
ram_bar = self._bar_html(ram_percent)
|
| 64 |
-
disk_bar = self._bar_html(disk_percent)
|
| 65 |
-
|
| 66 |
-
banners.append({
|
| 67 |
-
"id": "system-resources",
|
| 68 |
-
"type": "info",
|
| 69 |
-
"priority": 10,
|
| 70 |
-
"title": "System Resources",
|
| 71 |
-
"html": (
|
| 72 |
-
"<div class=\"system-resource-body\">"
|
| 73 |
-
"<div class=\"system-resource-meter\">"
|
| 74 |
-
"<div class=\"system-resource-label\">"
|
| 75 |
-
"<div class=\"system-resource-name\">CPU</div>"
|
| 76 |
-
f"<div class=\"system-resource-value\">{cpu_value}</div>"
|
| 77 |
-
"</div>"
|
| 78 |
-
f"{cpu_bar}"
|
| 79 |
-
"</div>"
|
| 80 |
-
"<div class=\"system-resource-meter\">"
|
| 81 |
-
"<div class=\"system-resource-label\">"
|
| 82 |
-
"<div class=\"system-resource-name\">RAM</div>"
|
| 83 |
-
f"<div class=\"system-resource-value\">{ram_value}</div>"
|
| 84 |
-
"</div>"
|
| 85 |
-
f"{ram_bar}"
|
| 86 |
-
"</div>"
|
| 87 |
-
"<div class=\"system-resource-meter\">"
|
| 88 |
-
"<div class=\"system-resource-label\">"
|
| 89 |
-
"<div class=\"system-resource-name\">Disk</div>"
|
| 90 |
-
f"<div class=\"system-resource-value\">{disk_value}</div>"
|
| 91 |
-
"</div>"
|
| 92 |
-
f"{disk_bar}"
|
| 93 |
-
"</div>"
|
| 94 |
-
"<div class=\"system-resource-footer\">"
|
| 95 |
-
"<div class=\"system-resource-detail\">"
|
| 96 |
-
"<div class=\"system-resource-detail-title\">Load (1/5/15)</div>"
|
| 97 |
-
f"<div class=\"system-resource-detail-value\">{load_value}</div>"
|
| 98 |
-
"</div>"
|
| 99 |
-
"<div class=\"system-resource-detail\">"
|
| 100 |
-
"<div class=\"system-resource-detail-title\">Net (since boot)</div>"
|
| 101 |
-
f"<div class=\"system-resource-detail-value\">{net_sent} sent / {net_recv} recv</div>"
|
| 102 |
-
"</div>"
|
| 103 |
-
"</div>"
|
| 104 |
-
"</div>"
|
| 105 |
-
),
|
| 106 |
-
"dismissible": True,
|
| 107 |
-
"source": "backend",
|
| 108 |
-
})
|
| 109 |
-
|
| 110 |
-
def _bar_html(self, percent: float | None) -> str:
|
| 111 |
-
if percent is None:
|
| 112 |
-
return ""
|
| 113 |
-
|
| 114 |
-
p = max(0.0, min(100.0, float(percent)))
|
| 115 |
-
if p >= 85:
|
| 116 |
-
color = "#ef4444"
|
| 117 |
-
elif p >= 70:
|
| 118 |
-
color = "#f59e0b"
|
| 119 |
-
else:
|
| 120 |
-
color = "#22c55e"
|
| 121 |
-
|
| 122 |
-
return (
|
| 123 |
-
"<div class=\"system-resource-track\">"
|
| 124 |
-
f"<span class=\"system-resource-fill\" style=\"--resource-value:{p:.0f}%;--resource-color:{color};\"></span>"
|
| 125 |
-
"</div>"
|
| 126 |
-
)
|
| 127 |
-
|
| 128 |
-
def _get_load_average(self) -> tuple[float, float, float] | None:
|
| 129 |
-
try:
|
| 130 |
-
return os.getloadavg()
|
| 131 |
-
except Exception:
|
| 132 |
-
return None
|
| 133 |
-
|
| 134 |
-
def _get_disk_usage(self) -> tuple[float | None, float | None, float | None, str]:
|
| 135 |
-
for path in ["/", os.path.expanduser("~")]:
|
| 136 |
-
try:
|
| 137 |
-
usage = psutil.disk_usage(path)
|
| 138 |
-
used_gb = usage.used / (1024 ** 3)
|
| 139 |
-
total_gb = usage.total / (1024 ** 3)
|
| 140 |
-
return usage.percent, used_gb, total_gb, path
|
| 141 |
-
except Exception:
|
| 142 |
-
continue
|
| 143 |
-
return None, None, None, "/"
|
| 144 |
-
|
| 145 |
-
def _format_bytes(self, value: int) -> str:
|
| 146 |
-
size = float(value)
|
| 147 |
-
for unit in ["B", "KB", "MB", "GB", "TB", "PB"]:
|
| 148 |
-
if size < 1024:
|
| 149 |
-
return f"{size:.1f} {unit}"
|
| 150 |
-
size /= 1024
|
| 151 |
-
return f"{size:.1f} EB"
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:c25cebb701f5ee4166d857d7bd34ea1d149507108691cd94cc78c553a606ec3d
|
| 3 |
+
size 5422
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
extensions/python/before_main_llm_call/AGENTS.md
CHANGED
|
@@ -1,26 +1,3 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
- Own backend behavior that runs immediately before the main LLM call.
|
| 6 |
-
|
| 7 |
-
## Ownership
|
| 8 |
-
|
| 9 |
-
- Ordered Python files own pre-call logging or context preparation for streaming/model execution.
|
| 10 |
-
|
| 11 |
-
## Local Contracts
|
| 12 |
-
|
| 13 |
-
- Do not mutate prompt or history data unless the hook contract explicitly passes mutable state for that purpose.
|
| 14 |
-
- Avoid logging secrets, hidden prompt sections, or private user data.
|
| 15 |
-
|
| 16 |
-
## Work Guidance
|
| 17 |
-
|
| 18 |
-
- Keep this hook light because it sits on the main model hot path.
|
| 19 |
-
|
| 20 |
-
## Verification
|
| 21 |
-
|
| 22 |
-
- Run targeted model-call or streaming tests after behavior changes.
|
| 23 |
-
|
| 24 |
-
## Child DOX Index
|
| 25 |
-
|
| 26 |
-
No child DOX files.
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:9a6e854a5cf0d094abc2bc4da91833b82b0301d173ddff8537b16b341a60a868
|
| 3 |
+
size 655
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
extensions/python/before_main_llm_call/_10_log_for_stream.py
CHANGED
|
@@ -1,33 +1,3 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
import asyncio
|
| 5 |
-
from helpers.log import LogItem
|
| 6 |
-
from helpers import log
|
| 7 |
-
import math
|
| 8 |
-
import uuid
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
class LogForStream(Extension):
|
| 12 |
-
|
| 13 |
-
async def execute(self, loop_data: LoopData = LoopData(), text: str = "", **kwargs):
|
| 14 |
-
if not self.agent:
|
| 15 |
-
return
|
| 16 |
-
|
| 17 |
-
# create log message and store it in loop data temporary params
|
| 18 |
-
if "log_item_generating" not in loop_data.params_temporary:
|
| 19 |
-
loop_data.params_temporary["log_item_generating"] = (
|
| 20 |
-
self.agent.context.log.log(
|
| 21 |
-
type="agent",
|
| 22 |
-
heading=build_default_heading(self.agent),
|
| 23 |
-
id=str(uuid.uuid4()),
|
| 24 |
-
)
|
| 25 |
-
)
|
| 26 |
-
|
| 27 |
-
def build_heading(agent, text: str, icon: str = "network_intelligence"):
|
| 28 |
-
# Include agent identifier for all agents (A0:, A1:, A2:, etc.)
|
| 29 |
-
agent_prefix = f"{agent.agent_name}: "
|
| 30 |
-
return f"{agent_prefix}{text}"
|
| 31 |
-
|
| 32 |
-
def build_default_heading(agent):
|
| 33 |
-
return build_heading(agent, "Calling LLM...")
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:39f2b897c81318b9f399bd96aa5883bfa866bee8857a62cdd69061aacfed94ac
|
| 3 |
+
size 1107
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
extensions/python/error_format/AGENTS.md
CHANGED
|
@@ -1,26 +1,3 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
- Own backend error formatting and masking before errors are shown or logged.
|
| 6 |
-
|
| 7 |
-
## Ownership
|
| 8 |
-
|
| 9 |
-
- Ordered Python files own mutation of error-format data passed by the hook.
|
| 10 |
-
|
| 11 |
-
## Local Contracts
|
| 12 |
-
|
| 13 |
-
- Preserve secret masking and safe user-facing error messages.
|
| 14 |
-
- Do not expose raw tokens, credentials, hidden prompts, or private payloads.
|
| 15 |
-
|
| 16 |
-
## Work Guidance
|
| 17 |
-
|
| 18 |
-
- Keep masking rules conservative and synchronized with tool/model error surfaces.
|
| 19 |
-
|
| 20 |
-
## Verification
|
| 21 |
-
|
| 22 |
-
- Test or inspect representative masked and unmasked error paths after changes.
|
| 23 |
-
|
| 24 |
-
## Child DOX Index
|
| 25 |
-
|
| 26 |
-
No child DOX files.
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:9b7b73348ce16977cdbdcb128c99408b750a985698adf49d8c4a8c2976c2b059
|
| 3 |
+
size 616
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
extensions/python/error_format/_10_mask_errors.py
CHANGED
|
@@ -1,20 +1,3 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
class MaskErrorSecrets(Extension):
|
| 6 |
-
|
| 7 |
-
async def execute(self, **kwargs):
|
| 8 |
-
if not self.agent:
|
| 9 |
-
return
|
| 10 |
-
|
| 11 |
-
# Get error data from kwargs
|
| 12 |
-
msg = kwargs.get("msg")
|
| 13 |
-
if not msg:
|
| 14 |
-
return
|
| 15 |
-
|
| 16 |
-
secrets_mgr = get_secrets_manager(self.agent.context)
|
| 17 |
-
|
| 18 |
-
# Mask the error message
|
| 19 |
-
if "message" in msg:
|
| 20 |
-
msg["message"] = secrets_mgr.mask_values(msg["message"])
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:30811f67fa20158348d9bd71dc8ad3c11c5562330e090d9fcae9ef2e34d9dd18
|
| 3 |
+
size 523
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
extensions/python/hist_add_before/AGENTS.md
CHANGED
|
@@ -1,26 +1,3 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
- Own preprocessing before messages are added to agent history.
|
| 6 |
-
|
| 7 |
-
## Ownership
|
| 8 |
-
|
| 9 |
-
- Ordered Python files own history content masking before persistence or model reuse.
|
| 10 |
-
|
| 11 |
-
## Local Contracts
|
| 12 |
-
|
| 13 |
-
- Preserve secret and sensitive-content masking before history storage.
|
| 14 |
-
- Do not remove fields required by downstream history organization or replay.
|
| 15 |
-
|
| 16 |
-
## Work Guidance
|
| 17 |
-
|
| 18 |
-
- Coordinate history mutation changes with message persistence and plugin-owned history consumers.
|
| 19 |
-
|
| 20 |
-
## Verification
|
| 21 |
-
|
| 22 |
-
- Test message history insertion for masked content after changes.
|
| 23 |
-
|
| 24 |
-
## Child DOX Index
|
| 25 |
-
|
| 26 |
-
No child DOX files.
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:5857c34d73e867c3034d4a2edad9d2e054469e9b2a81b5ee843fcd8ee8547e23
|
| 3 |
+
size 629
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
extensions/python/hist_add_before/_10_mask_content.py
CHANGED
|
@@ -1,35 +1,3 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
class MaskHistoryContent(Extension):
|
| 6 |
-
|
| 7 |
-
def execute(self, **kwargs):
|
| 8 |
-
if not self.agent:
|
| 9 |
-
return
|
| 10 |
-
|
| 11 |
-
# Get content data from kwargs
|
| 12 |
-
content_data = kwargs.get("content_data")
|
| 13 |
-
if not content_data:
|
| 14 |
-
return
|
| 15 |
-
|
| 16 |
-
try:
|
| 17 |
-
secrets_mgr = get_secrets_manager(self.agent.context)
|
| 18 |
-
|
| 19 |
-
# Mask the content before adding to history
|
| 20 |
-
content_data["content"] = self._mask_content(content_data["content"], secrets_mgr)
|
| 21 |
-
except Exception as e:
|
| 22 |
-
# If masking fails, proceed without masking
|
| 23 |
-
pass
|
| 24 |
-
|
| 25 |
-
def _mask_content(self, content, secrets_mgr):
|
| 26 |
-
"""Recursively mask secrets in message content."""
|
| 27 |
-
if isinstance(content, str):
|
| 28 |
-
return secrets_mgr.mask_values(content)
|
| 29 |
-
elif isinstance(content, list):
|
| 30 |
-
return [self._mask_content(item, secrets_mgr) for item in content]
|
| 31 |
-
elif isinstance(content, dict):
|
| 32 |
-
return {k: self._mask_content(v, secrets_mgr) for k, v in content.items()}
|
| 33 |
-
else:
|
| 34 |
-
# For other types, return as-is
|
| 35 |
-
return content
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:eb613a29492b4e9fa9b238de709d3fcee747b7ab6dee78e7871b0371dafb3f41
|
| 3 |
+
size 1212
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
extensions/python/hist_add_tool_result/AGENTS.md
CHANGED
|
@@ -1,27 +1,3 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
- Own processing after tool results are added to history.
|
| 6 |
-
|
| 7 |
-
## Ownership
|
| 8 |
-
|
| 9 |
-
- Ordered Python files own tool-call file persistence and related history side effects.
|
| 10 |
-
|
| 11 |
-
## Local Contracts
|
| 12 |
-
|
| 13 |
-
- Preserve tool result traceability without leaking secrets.
|
| 14 |
-
- Keep file artifacts inside expected runtime/user-owned paths.
|
| 15 |
-
- Skip BACKGROUND contexts; background workers must remain ephemeral and must not create chat message files.
|
| 16 |
-
|
| 17 |
-
## Work Guidance
|
| 18 |
-
|
| 19 |
-
- Coordinate changes with tool output storage and chat persistence behavior.
|
| 20 |
-
|
| 21 |
-
## Verification
|
| 22 |
-
|
| 23 |
-
- Smoke-test a tool call that produces persisted output after changes.
|
| 24 |
-
|
| 25 |
-
## Child DOX Index
|
| 26 |
-
|
| 27 |
-
No child DOX files.
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:b7fa7f5240203dec28a2b603a075b29bcbdaeecaf77450cb1dcf5f410577ffc7
|
| 3 |
+
size 692
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
extensions/python/hist_add_tool_result/_90_save_tool_call_file.py
CHANGED
|
@@ -1,44 +1,3 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
from helpers import files, persist_chat
|
| 5 |
-
import os, re
|
| 6 |
-
|
| 7 |
-
LEN_MIN = 500
|
| 8 |
-
|
| 9 |
-
class SaveToolCallFile(Extension):
|
| 10 |
-
def execute(self, data: dict[str, Any] | None = None, **kwargs):
|
| 11 |
-
if not self.agent:
|
| 12 |
-
return
|
| 13 |
-
|
| 14 |
-
if self.agent.context.type == AgentContextType.BACKGROUND:
|
| 15 |
-
return
|
| 16 |
-
|
| 17 |
-
if not data:
|
| 18 |
-
return
|
| 19 |
-
|
| 20 |
-
# get tool call result
|
| 21 |
-
result = data.get("tool_result") if isinstance(data, dict) else None
|
| 22 |
-
if result is None:
|
| 23 |
-
return
|
| 24 |
-
|
| 25 |
-
# skip short results
|
| 26 |
-
if len(str(result)) < LEN_MIN:
|
| 27 |
-
return
|
| 28 |
-
|
| 29 |
-
# message files directory
|
| 30 |
-
msgs_folder = persist_chat.get_chat_msg_files_folder(self.agent.context.id)
|
| 31 |
-
os.makedirs(msgs_folder, exist_ok=True)
|
| 32 |
-
|
| 33 |
-
# count the files in the directory
|
| 34 |
-
last_num = len(os.listdir(msgs_folder))
|
| 35 |
-
|
| 36 |
-
# create new file
|
| 37 |
-
new_file = files.get_abs_path(msgs_folder, f"{last_num+1}.txt")
|
| 38 |
-
files.write_file(
|
| 39 |
-
new_file,
|
| 40 |
-
result,
|
| 41 |
-
)
|
| 42 |
-
|
| 43 |
-
# add the path to the history
|
| 44 |
-
data["file"] = new_file
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:8dd610d93ebf73e70c78f2eb476b1c766dae1ecf330f4597b894064a21e03874
|
| 3 |
+
size 1208
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
extensions/python/job_loop/AGENTS.md
CHANGED
|
@@ -1,26 +1,3 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
- Own periodic backend maintenance jobs.
|
| 6 |
-
|
| 7 |
-
## Ownership
|
| 8 |
-
|
| 9 |
-
- Ordered Python files own cleanup of expired API chats, cache trimming, and future job-loop tasks.
|
| 10 |
-
|
| 11 |
-
## Local Contracts
|
| 12 |
-
|
| 13 |
-
- Jobs must be idempotent and safe to run repeatedly.
|
| 14 |
-
- Keep cleanup scoped to owned caches, temporary contexts, or documented runtime state.
|
| 15 |
-
|
| 16 |
-
## Work Guidance
|
| 17 |
-
|
| 18 |
-
- Avoid expensive work on every loop; use timestamps or thresholds when practical.
|
| 19 |
-
|
| 20 |
-
## Verification
|
| 21 |
-
|
| 22 |
-
- Run targeted cleanup/cache tests or smoke-test job-loop startup after changes.
|
| 23 |
-
|
| 24 |
-
## Child DOX Index
|
| 25 |
-
|
| 26 |
-
No child DOX files.
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:a6af0f3ca610f74f000248f7483e06b217b803155116f24fd818137c87ae8eb4
|
| 3 |
+
size 600
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
extensions/python/job_loop/_20_cleanup_expired_api_chats.py
CHANGED
|
@@ -1,63 +1,3 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
from agent import AgentContext
|
| 5 |
-
from helpers import persist_chat
|
| 6 |
-
from helpers.extension import Extension
|
| 7 |
-
from helpers.print_style import PrintStyle
|
| 8 |
-
from helpers.state_monitor_integration import mark_dirty_all
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
CHECK_INTERVAL = timedelta(hours=1)
|
| 12 |
-
LIFETIME_KEY = "lifetime_hours"
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
class CleanupExpiredApiChats(Extension):
|
| 16 |
-
_last_check: datetime | None = None
|
| 17 |
-
|
| 18 |
-
async def execute(self, data: dict[str, Any] | None = None, **kwargs):
|
| 19 |
-
now = datetime.now(timezone.utc)
|
| 20 |
-
if type(self)._last_check and now - type(self)._last_check < CHECK_INTERVAL:
|
| 21 |
-
return
|
| 22 |
-
type(self)._last_check = now
|
| 23 |
-
|
| 24 |
-
removed = 0
|
| 25 |
-
for context in list(AgentContext.all()):
|
| 26 |
-
lifetime_hours = context.get_data(LIFETIME_KEY)
|
| 27 |
-
if lifetime_hours is None:
|
| 28 |
-
continue
|
| 29 |
-
|
| 30 |
-
try:
|
| 31 |
-
lifetime = timedelta(hours=float(lifetime_hours))
|
| 32 |
-
except (TypeError, ValueError):
|
| 33 |
-
PrintStyle.error(
|
| 34 |
-
f"Invalid chat lifetime for {context.id}: {lifetime_hours}"
|
| 35 |
-
)
|
| 36 |
-
continue
|
| 37 |
-
|
| 38 |
-
if lifetime <= timedelta(0) or context.is_running():
|
| 39 |
-
continue
|
| 40 |
-
|
| 41 |
-
last_message = _as_utc(context.last_message)
|
| 42 |
-
if now - last_message <= lifetime:
|
| 43 |
-
continue
|
| 44 |
-
|
| 45 |
-
try:
|
| 46 |
-
context.reset()
|
| 47 |
-
AgentContext.remove(context.id)
|
| 48 |
-
persist_chat.remove_chat(context.id)
|
| 49 |
-
removed += 1
|
| 50 |
-
PrintStyle().print(f"Cleaned up expired API chat: {context.id}")
|
| 51 |
-
except Exception as e:
|
| 52 |
-
PrintStyle.error(f"Failed to cleanup expired API chat {context.id}: {e}")
|
| 53 |
-
|
| 54 |
-
if removed:
|
| 55 |
-
mark_dirty_all(reason="job_loop.CleanupExpiredApiChats")
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
def _as_utc(value: datetime | None) -> datetime:
|
| 59 |
-
if value is None:
|
| 60 |
-
return datetime.fromtimestamp(0, timezone.utc)
|
| 61 |
-
if value.tzinfo is None:
|
| 62 |
-
return value.replace(tzinfo=timezone.utc)
|
| 63 |
-
return value.astimezone(timezone.utc)
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:77ff57423672bedcbdf501f27cbcb7816192e088e2e98893be9c76ae819e67a9
|
| 3 |
+
size 2119
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
extensions/python/job_loop/_50_trim_cache.py
CHANGED
|
@@ -1,9 +1,3 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
class SaveToolCallFile(Extension):
|
| 7 |
-
def execute(self, data: dict[str, Any] | None = None, **kwargs):
|
| 8 |
-
# trim unused cache entries
|
| 9 |
-
cache.trim_cache("*", seconds=300)
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:a5b536371abc86345790f9014baa645fc7d33fcd0a1062dc0fc27c56b7948587
|
| 3 |
+
size 274
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
extensions/python/message_loop_end/AGENTS.md
CHANGED
|
@@ -1,27 +1,3 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
- Own backend behavior that runs after a message loop completes.
|
| 6 |
-
|
| 7 |
-
## Ownership
|
| 8 |
-
|
| 9 |
-
- Ordered Python files own history organization and chat persistence at loop end.
|
| 10 |
-
|
| 11 |
-
## Local Contracts
|
| 12 |
-
|
| 13 |
-
- Preserve history consistency before saving chats.
|
| 14 |
-
- Do not skip persistence for successful loops unless the hook contract explicitly permits it.
|
| 15 |
-
- History compression that rewrites local history must clear the active Responses provider continuation while preserving stored response IDs for cleanup.
|
| 16 |
-
|
| 17 |
-
## Work Guidance
|
| 18 |
-
|
| 19 |
-
- Coordinate changes with chat serialization, history organization, and WebUI refresh behavior.
|
| 20 |
-
|
| 21 |
-
## Verification
|
| 22 |
-
|
| 23 |
-
- Smoke-test sending a message, reloading the chat, and checking persisted history after changes.
|
| 24 |
-
|
| 25 |
-
## Child DOX Index
|
| 26 |
-
|
| 27 |
-
No child DOX files.
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:aad03752d410b9e80eef91fa1e1b5a45b7907f2085001f6591e47878495d6f5c
|
| 3 |
+
size 803
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
extensions/python/message_loop_end/_10_organize_history.py
CHANGED
|
@@ -1,30 +1,3 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
from helpers.history import clear_responses_provider_state
|
| 5 |
-
|
| 6 |
-
DATA_NAME_TASK = "_organize_history_task"
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
async def compress_history(agent) -> bool:
|
| 10 |
-
compressed = bool(await agent.history.compress())
|
| 11 |
-
if compressed:
|
| 12 |
-
clear_responses_provider_state(agent)
|
| 13 |
-
return compressed
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
class OrganizeHistory(Extension):
|
| 17 |
-
async def execute(self, loop_data: LoopData = LoopData(), **kwargs):
|
| 18 |
-
if not self.agent:
|
| 19 |
-
return
|
| 20 |
-
|
| 21 |
-
# is there a running task? if yes, skip this round, the wait extension will double check the context size
|
| 22 |
-
task: DeferredTask|None = self.agent.get_data(DATA_NAME_TASK)
|
| 23 |
-
if task and not task.is_ready():
|
| 24 |
-
return
|
| 25 |
-
|
| 26 |
-
# start task
|
| 27 |
-
task = DeferredTask(thread_name=THREAD_BACKGROUND)
|
| 28 |
-
task.start_task(compress_history, self.agent)
|
| 29 |
-
# set to agent to be able to wait for it
|
| 30 |
-
self.agent.set_data(DATA_NAME_TASK, task)
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:70998648652bb1192f47f3bc4a4907a1b7860045bf6f76dbf075841cea0394bb
|
| 3 |
+
size 1047
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
extensions/python/message_loop_end/_90_save_chat.py
CHANGED
|
@@ -1,15 +1,3 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
class SaveChat(Extension):
|
| 7 |
-
async def execute(self, loop_data: LoopData = LoopData(), **kwargs):
|
| 8 |
-
if not self.agent:
|
| 9 |
-
return
|
| 10 |
-
|
| 11 |
-
# Skip saving BACKGROUND contexts as they should be ephemeral
|
| 12 |
-
if self.agent.context.type == AgentContextType.BACKGROUND:
|
| 13 |
-
return
|
| 14 |
-
|
| 15 |
-
persist_chat.save_tmp_chat(self.agent.context)
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:8f2efeb0b9ddafa494eb58cdc1f649eb2edf9f0ae7c16d8f58d6cb95d6bc87ab
|
| 3 |
+
size 479
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
extensions/python/message_loop_prompts_after/AGENTS.md
CHANGED
|
@@ -1,33 +1,3 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
- Own prompt protocol, prompt extras, and history reattachment around primary message-loop prompt construction.
|
| 6 |
-
|
| 7 |
-
## Ownership
|
| 8 |
-
|
| 9 |
-
- Ordered Python files own current datetime, relevant-skill hints, loaded-skill history reattachment, agent info, parallel job status, and workdir extras injection.
|
| 10 |
-
- Explicitly loaded skill bodies belong in tool-result history with metadata so they can survive persistence and be reattached after compaction.
|
| 11 |
-
- Explicitly loaded skill IDs are chat-wide context data, not agent-local state.
|
| 12 |
-
- Skills must not write selected or loaded skill bodies into protocol or extras.
|
| 13 |
-
|
| 14 |
-
## Local Contracts
|
| 15 |
-
|
| 16 |
-
- Keep injected content bounded and clearly attributed.
|
| 17 |
-
- Preserve ordering where later prompt extras depend on earlier recall or load results.
|
| 18 |
-
- Do not expose secrets or private files from workdir extras.
|
| 19 |
-
- Relevant-skill recall should search the raw user message when available, not the rendered history wrapper.
|
| 20 |
-
- Relevant-skill hints must not advertise loading when profile policy blocks
|
| 21 |
-
`skills_tool`.
|
| 22 |
-
|
| 23 |
-
## Work Guidance
|
| 24 |
-
|
| 25 |
-
- Coordinate prompt protocol, history-reattachment, and prompt-extra changes with skill, workdir, and profile contracts.
|
| 26 |
-
|
| 27 |
-
## Verification
|
| 28 |
-
|
| 29 |
-
- Inspect rendered prompt protocol/history/extras or run prompt-construction tests after changes.
|
| 30 |
-
|
| 31 |
-
## Child DOX Index
|
| 32 |
-
|
| 33 |
-
No child DOX files.
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:42e777c4abc98d45ef762257a7bd55f079df91a7b6dc1ef1bffbfc72b288cf4d
|
| 3 |
+
size 1383
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
extensions/python/message_loop_prompts_after/_60_include_current_datetime.py
CHANGED
|
@@ -1,19 +1,3 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
class IncludeCurrentDatetime(Extension):
|
| 7 |
-
async def execute(self, loop_data: LoopData = LoopData(), **kwargs):
|
| 8 |
-
if not self.agent:
|
| 9 |
-
return
|
| 10 |
-
|
| 11 |
-
current_datetime = Localization.get().now().strftime("%Y-%m-%d %H:%M:%S %Z")
|
| 12 |
-
|
| 13 |
-
# read prompt
|
| 14 |
-
datetime_prompt = self.agent.read_prompt(
|
| 15 |
-
"agent.system.datetime.md", date_time=current_datetime
|
| 16 |
-
)
|
| 17 |
-
|
| 18 |
-
# add current datetime to the loop data
|
| 19 |
-
loop_data.extras_temporary["current_datetime"] = datetime_prompt
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:6737327bbd60eb39b4cf9d581c243a472cba4f69e2abe6bb42f207970d3f601e
|
| 3 |
+
size 633
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
extensions/python/message_loop_prompts_after/_63_recall_relevant_skills.py
CHANGED
|
@@ -1,45 +1,3 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
class RecallRelevantSkills(Extension):
|
| 7 |
-
async def execute(self, loop_data: LoopData = LoopData(), **kwargs):
|
| 8 |
-
if not self.agent or loop_data.iteration != 0:
|
| 9 |
-
return
|
| 10 |
-
if not tool_policy.resolve_tool(self.agent, "skills_tool").allowed:
|
| 11 |
-
return
|
| 12 |
-
|
| 13 |
-
content = loop_data.user_message.content if loop_data.user_message else ""
|
| 14 |
-
if isinstance(content, dict):
|
| 15 |
-
user_instruction = str(content.get("user_message") or "").strip()
|
| 16 |
-
else:
|
| 17 |
-
user_instruction = (
|
| 18 |
-
loop_data.user_message.output_text() if loop_data.user_message else ""
|
| 19 |
-
).strip()
|
| 20 |
-
if len(user_instruction) < 8:
|
| 21 |
-
return
|
| 22 |
-
|
| 23 |
-
matches = skills_helper.search_skills(
|
| 24 |
-
user_instruction,
|
| 25 |
-
limit=6,
|
| 26 |
-
agent=self.agent,
|
| 27 |
-
)
|
| 28 |
-
if not matches:
|
| 29 |
-
return
|
| 30 |
-
|
| 31 |
-
lines: list[str] = []
|
| 32 |
-
for skill in matches:
|
| 33 |
-
name = skill.name.strip().replace("\n", " ")[:100]
|
| 34 |
-
desc = (skill.description or "").replace("\n", " ").strip()
|
| 35 |
-
if len(desc) > 220:
|
| 36 |
-
desc = desc[:220].rstrip() + "…"
|
| 37 |
-
lines.append(f"- {name}: {desc}")
|
| 38 |
-
|
| 39 |
-
if not lines:
|
| 40 |
-
return
|
| 41 |
-
|
| 42 |
-
loop_data.extras_temporary["relevant_skills"] = self.agent.read_prompt(
|
| 43 |
-
"agent.system.skills.relevant.md",
|
| 44 |
-
skills="\n".join(lines),
|
| 45 |
-
)
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:130e5e731e029d363cf3cf361b33613c846a40627a81fb0eb2967c568fff24ea
|
| 3 |
+
size 1544
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
extensions/python/message_loop_prompts_after/_65_include_loaded_skills.py
CHANGED
|
@@ -1,78 +1,3 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
SKILL_REATTACHMENT_TOKEN_BUDGET = 12_000
|
| 7 |
-
SKILL_REATTACHMENT_HEADER = (
|
| 8 |
-
"Reattached loaded skill instructions after history compaction."
|
| 9 |
-
)
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
class IncludeLoadedSkills(Extension):
|
| 13 |
-
async def execute(self, loop_data: LoopData = LoopData(), **kwargs):
|
| 14 |
-
if not self.agent:
|
| 15 |
-
return
|
| 16 |
-
|
| 17 |
-
skill_names = skills.get_loaded_skill_names(self.agent)
|
| 18 |
-
if not skill_names:
|
| 19 |
-
return
|
| 20 |
-
|
| 21 |
-
# Loaded skill bodies live in tool-result history. This hook only keeps
|
| 22 |
-
# the ledger clean and restores bodies that compaction hid.
|
| 23 |
-
visible_skill_names = []
|
| 24 |
-
loaded_skills = []
|
| 25 |
-
for skill_name in skill_names:
|
| 26 |
-
skill = skills.find_skill(skill_name, agent=self.agent)
|
| 27 |
-
if not skill:
|
| 28 |
-
continue
|
| 29 |
-
visible_skill_names.append(skill.name)
|
| 30 |
-
loaded_skills.append(skill)
|
| 31 |
-
skills.set_loaded_skill_names(self.agent, visible_skill_names)
|
| 32 |
-
|
| 33 |
-
self._reattach_missing_skill_bodies(loop_data, loaded_skills)
|
| 34 |
-
|
| 35 |
-
def _reattach_missing_skill_bodies(self, loop_data: LoopData, loaded_skills):
|
| 36 |
-
if not self.agent or not loaded_skills:
|
| 37 |
-
return
|
| 38 |
-
|
| 39 |
-
visible_skill_names = _visible_skill_names(loop_data.history_output)
|
| 40 |
-
selected = []
|
| 41 |
-
used_tokens = 0
|
| 42 |
-
|
| 43 |
-
for skill in reversed(loaded_skills):
|
| 44 |
-
if skill.name in visible_skill_names:
|
| 45 |
-
continue
|
| 46 |
-
|
| 47 |
-
skill_data = skills.load_skill_for_agent(
|
| 48 |
-
skill_name=skill.name,
|
| 49 |
-
agent=self.agent,
|
| 50 |
-
)
|
| 51 |
-
message = f"{SKILL_REATTACHMENT_HEADER}\n\n{skill_data}"
|
| 52 |
-
message_tokens = tokens.approximate_tokens(message)
|
| 53 |
-
if used_tokens + message_tokens > SKILL_REATTACHMENT_TOKEN_BUDGET:
|
| 54 |
-
continue
|
| 55 |
-
|
| 56 |
-
selected.append((skill, message))
|
| 57 |
-
used_tokens += message_tokens
|
| 58 |
-
|
| 59 |
-
for skill, message in reversed(selected):
|
| 60 |
-
history_message = self.agent.hist_add_tool_result(
|
| 61 |
-
"skills_tool",
|
| 62 |
-
message,
|
| 63 |
-
skill_instructions={
|
| 64 |
-
"name": skill.name,
|
| 65 |
-
"path": str(skill.path),
|
| 66 |
-
"source": "skills_tool:reattach",
|
| 67 |
-
"content_included": True,
|
| 68 |
-
},
|
| 69 |
-
)
|
| 70 |
-
loop_data.history_output.extend(history_message.output())
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
def _visible_skill_names(history_output) -> set[str]:
|
| 74 |
-
return {
|
| 75 |
-
name
|
| 76 |
-
for message in history_output or []
|
| 77 |
-
if (name := skills.skill_instruction_name(message))
|
| 78 |
-
}
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:3d911949e4103bf7d9a756a85517d4cca75aeab223d8f57956244fdf110a1cd3
|
| 3 |
+
size 2668
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
extensions/python/message_loop_prompts_after/_70_include_agent_info.py
CHANGED
|
@@ -1,27 +1,3 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
class IncludeAgentInfo(Extension):
|
| 6 |
-
async def execute(self, loop_data: LoopData = LoopData(), **kwargs):
|
| 7 |
-
if not self.agent:
|
| 8 |
-
return
|
| 9 |
-
|
| 10 |
-
# read prompt
|
| 11 |
-
from plugins._model_config.helpers.model_config import (
|
| 12 |
-
get_chat_model_config,
|
| 13 |
-
get_effective_preset_name,
|
| 14 |
-
)
|
| 15 |
-
chat_cfg = get_chat_model_config(self.agent)
|
| 16 |
-
preset_name = get_effective_preset_name(self.agent)
|
| 17 |
-
|
| 18 |
-
agent_info_prompt = self.agent.read_prompt(
|
| 19 |
-
"agent.extras.agent_info.md",
|
| 20 |
-
number=self.agent.number,
|
| 21 |
-
profile=self.agent.config.profile or "Default",
|
| 22 |
-
llm=chat_cfg.get("provider", "") + "/" + chat_cfg.get("name", ""),
|
| 23 |
-
preset=preset_name,
|
| 24 |
-
)
|
| 25 |
-
|
| 26 |
-
# add agent info to the prompt
|
| 27 |
-
loop_data.extras_temporary["agent_info"] = agent_info_prompt
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:c10a045b764ddc51c2f00ba3e7a9cc702fd8acd3b31f3b7942707eeea1c432e9
|
| 3 |
+
size 931
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
extensions/python/message_loop_prompts_after/_72_include_parallel_jobs.py
CHANGED
|
@@ -1,13 +1,3 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
class IncludeParallelJobs(Extension):
|
| 7 |
-
async def execute(self, loop_data: LoopData = LoopData(), **kwargs):
|
| 8 |
-
if not self.agent:
|
| 9 |
-
return
|
| 10 |
-
|
| 11 |
-
extras = await parallel_tools.build_parallel_jobs_extras(self.agent)
|
| 12 |
-
if extras:
|
| 13 |
-
loop_data.extras_temporary["parallel_jobs"] = extras
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:2d4e5220acd60cb3de270e2e828db61c999c951ab5d9f9bbb9f5457bc1a15f2b
|
| 3 |
+
size 423
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
extensions/python/message_loop_prompts_after/_75_include_workdir_extras.py
CHANGED
|
@@ -1,96 +1,3 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
from helpers import settings
|
| 5 |
-
from helpers import runtime
|
| 6 |
-
from helpers import file_tree
|
| 7 |
-
from helpers import files
|
| 8 |
-
|
| 9 |
-
class IncludeWorkdirExtras(Extension):
|
| 10 |
-
async def execute(self, loop_data: LoopData = LoopData(), **kwargs):
|
| 11 |
-
if not self.agent:
|
| 12 |
-
return
|
| 13 |
-
|
| 14 |
-
project_name = projects.get_context_project_name(self.agent.context)
|
| 15 |
-
|
| 16 |
-
enabled = False
|
| 17 |
-
max_depth = 0
|
| 18 |
-
max_files = 0
|
| 19 |
-
max_folders = 0
|
| 20 |
-
max_lines = 0
|
| 21 |
-
gitignore_raw = ""
|
| 22 |
-
folder = ""
|
| 23 |
-
file_structure = ""
|
| 24 |
-
|
| 25 |
-
if project_name:
|
| 26 |
-
project = projects.load_basic_project_data(project_name)
|
| 27 |
-
enabled = project["file_structure"]["enabled"]
|
| 28 |
-
|
| 29 |
-
if not enabled:
|
| 30 |
-
return
|
| 31 |
-
|
| 32 |
-
max_depth = project["file_structure"]["max_depth"]
|
| 33 |
-
gitignore_raw = project["file_structure"]["gitignore"]
|
| 34 |
-
|
| 35 |
-
folder = projects.get_project_folder(project_name)
|
| 36 |
-
if runtime.is_development():
|
| 37 |
-
folder = files.normalize_a0_path(folder)
|
| 38 |
-
|
| 39 |
-
file_structure = projects.get_file_structure(project_name)
|
| 40 |
-
else:
|
| 41 |
-
set = settings.get_settings_for_prompt()
|
| 42 |
-
enabled = bool(set["workdir_show"])
|
| 43 |
-
|
| 44 |
-
if not enabled:
|
| 45 |
-
return
|
| 46 |
-
|
| 47 |
-
max_depth = set["workdir_max_depth"]
|
| 48 |
-
max_files = set["workdir_max_files"]
|
| 49 |
-
max_folders = set["workdir_max_folders"]
|
| 50 |
-
max_lines = set["workdir_max_lines"]
|
| 51 |
-
gitignore_raw = set["workdir_gitignore"]
|
| 52 |
-
|
| 53 |
-
folder = set["workdir_path"]
|
| 54 |
-
scan_path = files.get_abs_path_development(folder)
|
| 55 |
-
|
| 56 |
-
files.create_dir(scan_path)
|
| 57 |
-
|
| 58 |
-
file_structure = str(
|
| 59 |
-
file_tree.file_tree(
|
| 60 |
-
scan_path,
|
| 61 |
-
max_depth=max_depth,
|
| 62 |
-
max_files=max_files,
|
| 63 |
-
max_folders=max_folders,
|
| 64 |
-
max_lines=max_lines,
|
| 65 |
-
ignore=gitignore_raw,
|
| 66 |
-
output_mode=file_tree.OUTPUT_MODE_STRING,
|
| 67 |
-
)
|
| 68 |
-
)
|
| 69 |
-
|
| 70 |
-
gitignore = cleanup_gitignore(gitignore_raw)
|
| 71 |
-
|
| 72 |
-
file_structure_prompt = self.agent.read_prompt(
|
| 73 |
-
"agent.extras.workdir_structure.md",
|
| 74 |
-
max_depth=max_depth,
|
| 75 |
-
gitignore=gitignore,
|
| 76 |
-
folder=folder,
|
| 77 |
-
file_structure=file_structure,
|
| 78 |
-
)
|
| 79 |
-
|
| 80 |
-
loop_data.extras_temporary["project_file_structure"] = file_structure_prompt
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
def cleanup_gitignore(gitignore_raw: str) -> str:
|
| 84 |
-
"""Process gitignore: split lines, strip, remove comments, remove empty lines."""
|
| 85 |
-
gitignore_lines = []
|
| 86 |
-
for line in gitignore_raw.split('\n'):
|
| 87 |
-
# Strip whitespace
|
| 88 |
-
line = line.strip()
|
| 89 |
-
# Remove inline comments (everything after #)
|
| 90 |
-
if '#' in line:
|
| 91 |
-
line = line.split('#')[0].strip()
|
| 92 |
-
# Keep only non-empty lines
|
| 93 |
-
if line:
|
| 94 |
-
gitignore_lines.append(line)
|
| 95 |
-
|
| 96 |
-
return '\n'.join(gitignore_lines) if gitignore_lines else "nothing ignored"
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:bc46c3d0e739e5f9f66e753ff11d589dd857eff3ad328d9b00244e65ab307dcd
|
| 3 |
+
size 3173
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|