Leon4gr45 commited on
Commit
dcf38fc
·
verified ·
1 Parent(s): 9de2964

Upload folder using huggingface_hub (part 2)

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitattributes +233 -0
  2. docker/base/Dockerfile +3 -40
  3. docker/base/build.txt +3 -18
  4. docker/base/fs/etc/searxng/limiter.toml +3 -33
  5. docker/base/fs/etc/searxng/settings.yml +3 -91
  6. docker/base/fs/ins/after_install.sh +3 -5
  7. docker/base/fs/ins/configure_ssh.sh +3 -6
  8. docker/base/fs/ins/install_base_packages1.sh +3 -11
  9. docker/base/fs/ins/install_base_packages2.sh +3 -10
  10. docker/base/fs/ins/install_base_packages3.sh +3 -13
  11. docker/base/fs/ins/install_base_packages4.sh +3 -9
  12. docker/base/fs/ins/install_python.sh +3 -73
  13. docker/base/fs/ins/install_searxng.sh +3 -29
  14. docker/base/fs/ins/install_searxng2.sh +3 -36
  15. docker/run/AGENTS.md +3 -43
  16. docker/run/Dockerfile +3 -36
  17. docker/run/build.txt +3 -42
  18. docker/run/docker-compose.yml +3 -14
  19. docker/run/fs/etc/nginx/nginx.conf +3 -31
  20. docker/run/fs/etc/searxng/limiter.toml +3 -33
  21. docker/run/fs/etc/searxng/settings.yml +3 -98
  22. docker/run/fs/etc/supervisor/conf.d/supervisord.conf +3 -95
  23. docker/run/fs/exe/huggingface-entrypoint.sh +3 -42
  24. docker/run/fs/exe/initialize.sh +3 -63
  25. docker/run/fs/exe/node_eval.js +3 -62
  26. docker/run/fs/exe/run_A0.sh +3 -7
  27. docker/run/fs/exe/run_searxng.sh +3 -10
  28. docker/run/fs/exe/run_tunnel_api.sh +3 -18
  29. docker/run/fs/exe/self_update_manager.py +3 -1507
  30. docker/run/fs/exe/supervisor_event_listener.py +3 -47
  31. docker/run/fs/exe/trigger_self_update.sh +3 -6
  32. docker/run/fs/ins/copy_A0.sh +3 -12
  33. docker/run/fs/ins/install_A0.sh +3 -44
  34. docker/run/fs/ins/install_A02.sh +3 -17
  35. docker/run/fs/ins/install_additional.sh +3 -94
  36. docker/run/fs/ins/install_playwright.sh +3 -13
  37. docker/run/fs/ins/post_install.sh +3 -6
  38. docker/run/fs/ins/pre_install.sh +3 -13
  39. docker/run/fs/ins/setup_ssh.sh +3 -7
  40. docker/run/fs/ins/setup_venv.sh +3 -12
  41. docker/run/fs/per/root/.bashrc +3 -9
  42. docker/run/fs/per/root/.profile +3 -9
  43. docs/AGENTS.md +3 -35
  44. docs/README.md +3 -159
  45. docs/developer/architecture.md +3 -32
  46. docs/developer/connectivity.md +3 -55
  47. docs/developer/contributing-skills.md +3 -395
  48. docs/developer/extensions.md +3 -46
  49. docs/developer/mcp-configuration.md +3 -80
  50. docs/developer/notifications.md +3 -133
.gitattributes CHANGED
@@ -1,3 +1,236 @@
1
  version https://git-lfs.github.com/spec/v1
2
  oid sha256:56c89d9018842070bb8dd1397378f26b814d30f4f7c56d8ff8788dbae1f83682
3
  size 72
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  version https://git-lfs.github.com/spec/v1
2
  oid sha256:56c89d9018842070bb8dd1397378f26b814d30f4f7c56d8ff8788dbae1f83682
3
  size 72
4
+ docker/base/Dockerfile filter=lfs diff=lfs merge=lfs -text
5
+ docker/base/build.txt filter=lfs diff=lfs merge=lfs -text
6
+ docker/base/fs/etc/searxng/limiter.toml filter=lfs diff=lfs merge=lfs -text
7
+ docker/base/fs/etc/searxng/settings.yml filter=lfs diff=lfs merge=lfs -text
8
+ docker/base/fs/ins/after_install.sh filter=lfs diff=lfs merge=lfs -text
9
+ docker/base/fs/ins/configure_ssh.sh filter=lfs diff=lfs merge=lfs -text
10
+ docker/base/fs/ins/install_base_packages1.sh filter=lfs diff=lfs merge=lfs -text
11
+ docker/base/fs/ins/install_base_packages2.sh filter=lfs diff=lfs merge=lfs -text
12
+ docker/base/fs/ins/install_base_packages3.sh filter=lfs diff=lfs merge=lfs -text
13
+ docker/base/fs/ins/install_base_packages4.sh filter=lfs diff=lfs merge=lfs -text
14
+ docker/base/fs/ins/install_python.sh filter=lfs diff=lfs merge=lfs -text
15
+ docker/base/fs/ins/install_searxng.sh filter=lfs diff=lfs merge=lfs -text
16
+ docker/base/fs/ins/install_searxng2.sh filter=lfs diff=lfs merge=lfs -text
17
+ docker/run/AGENTS.md filter=lfs diff=lfs merge=lfs -text
18
+ docker/run/Dockerfile filter=lfs diff=lfs merge=lfs -text
19
+ docker/run/build.txt filter=lfs diff=lfs merge=lfs -text
20
+ docker/run/docker-compose.yml filter=lfs diff=lfs merge=lfs -text
21
+ docker/run/fs/etc/nginx/nginx.conf filter=lfs diff=lfs merge=lfs -text
22
+ docker/run/fs/etc/searxng/limiter.toml filter=lfs diff=lfs merge=lfs -text
23
+ docker/run/fs/etc/searxng/settings.yml filter=lfs diff=lfs merge=lfs -text
24
+ docker/run/fs/etc/supervisor/conf.d/supervisord.conf filter=lfs diff=lfs merge=lfs -text
25
+ docker/run/fs/exe/huggingface-entrypoint.sh filter=lfs diff=lfs merge=lfs -text
26
+ docker/run/fs/exe/initialize.sh filter=lfs diff=lfs merge=lfs -text
27
+ docker/run/fs/exe/node_eval.js filter=lfs diff=lfs merge=lfs -text
28
+ docker/run/fs/exe/run_A0.sh filter=lfs diff=lfs merge=lfs -text
29
+ docker/run/fs/exe/run_searxng.sh filter=lfs diff=lfs merge=lfs -text
30
+ docker/run/fs/exe/run_tunnel_api.sh filter=lfs diff=lfs merge=lfs -text
31
+ docker/run/fs/exe/self_update_manager.py filter=lfs diff=lfs merge=lfs -text
32
+ docker/run/fs/exe/supervisor_event_listener.py filter=lfs diff=lfs merge=lfs -text
33
+ docker/run/fs/exe/trigger_self_update.sh filter=lfs diff=lfs merge=lfs -text
34
+ docker/run/fs/ins/copy_A0.sh filter=lfs diff=lfs merge=lfs -text
35
+ docker/run/fs/ins/install_A0.sh filter=lfs diff=lfs merge=lfs -text
36
+ docker/run/fs/ins/install_A02.sh filter=lfs diff=lfs merge=lfs -text
37
+ docker/run/fs/ins/install_additional.sh filter=lfs diff=lfs merge=lfs -text
38
+ docker/run/fs/ins/install_playwright.sh filter=lfs diff=lfs merge=lfs -text
39
+ docker/run/fs/ins/post_install.sh filter=lfs diff=lfs merge=lfs -text
40
+ docker/run/fs/ins/pre_install.sh filter=lfs diff=lfs merge=lfs -text
41
+ docker/run/fs/ins/setup_ssh.sh filter=lfs diff=lfs merge=lfs -text
42
+ docker/run/fs/ins/setup_venv.sh filter=lfs diff=lfs merge=lfs -text
43
+ docker/run/fs/per/root/.bashrc filter=lfs diff=lfs merge=lfs -text
44
+ docker/run/fs/per/root/.profile filter=lfs diff=lfs merge=lfs -text
45
+ docs/AGENTS.md filter=lfs diff=lfs merge=lfs -text
46
+ docs/README.md filter=lfs diff=lfs merge=lfs -text
47
+ docs/developer/architecture.md filter=lfs diff=lfs merge=lfs -text
48
+ docs/developer/connectivity.md filter=lfs diff=lfs merge=lfs -text
49
+ docs/developer/contributing-skills.md filter=lfs diff=lfs merge=lfs -text
50
+ docs/developer/extensions.md filter=lfs diff=lfs merge=lfs -text
51
+ docs/developer/mcp-configuration.md filter=lfs diff=lfs merge=lfs -text
52
+ docs/developer/notifications.md filter=lfs diff=lfs merge=lfs -text
53
+ docs/developer/plugins.md filter=lfs diff=lfs merge=lfs -text
54
+ docs/developer/sharing-and-safety.md filter=lfs diff=lfs merge=lfs -text
55
+ docs/developer/websockets.md filter=lfs diff=lfs merge=lfs -text
56
+ docs/guides/a0-cli-connector.md filter=lfs diff=lfs merge=lfs -text
57
+ docs/guides/a2a-setup.md filter=lfs diff=lfs merge=lfs -text
58
+ docs/guides/agent-profiles.md filter=lfs diff=lfs merge=lfs -text
59
+ docs/guides/api-integration.md filter=lfs diff=lfs merge=lfs -text
60
+ docs/guides/browser.md filter=lfs diff=lfs merge=lfs -text
61
+ docs/guides/contribution.md filter=lfs diff=lfs merge=lfs -text
62
+ docs/guides/create-plugin.md filter=lfs diff=lfs merge=lfs -text
63
+ docs/guides/desktop.md filter=lfs diff=lfs merge=lfs -text
64
+ docs/guides/launcher.md filter=lfs diff=lfs merge=lfs -text
65
+ docs/guides/local-model-tool-use.md filter=lfs diff=lfs merge=lfs -text
66
+ docs/guides/mcp-setup.md filter=lfs diff=lfs merge=lfs -text
67
+ docs/guides/memory.md filter=lfs diff=lfs merge=lfs -text
68
+ docs/guides/model-presets.md filter=lfs diff=lfs merge=lfs -text
69
+ docs/guides/onboarding.md filter=lfs diff=lfs merge=lfs -text
70
+ docs/guides/projects.md filter=lfs diff=lfs merge=lfs -text
71
+ docs/guides/self-update.md filter=lfs diff=lfs merge=lfs -text
72
+ docs/guides/skills.md filter=lfs diff=lfs merge=lfs -text
73
+ docs/guides/troubleshooting.md filter=lfs diff=lfs merge=lfs -text
74
+ docs/guides/usage.md filter=lfs diff=lfs merge=lfs -text
75
+ docs/quickstart.md filter=lfs diff=lfs merge=lfs -text
76
+ docs/res/a0-vector-graphics/banner.svg filter=lfs diff=lfs merge=lfs -text
77
+ docs/res/a0-vector-graphics/dark.svg filter=lfs diff=lfs merge=lfs -text
78
+ docs/res/a0-vector-graphics/darkSymbol.svg filter=lfs diff=lfs merge=lfs -text
79
+ docs/res/a0-vector-graphics/horizontal_banner.svg filter=lfs diff=lfs merge=lfs -text
80
+ docs/res/a0-vector-graphics/light.svg filter=lfs diff=lfs merge=lfs -text
81
+ docs/res/a0-vector-graphics/lightSymbol.svg filter=lfs diff=lfs merge=lfs -text
82
+ docs/res/banner.png filter=lfs diff=lfs merge=lfs -text
83
+ docs/res/banner_high.png filter=lfs diff=lfs merge=lfs -text
84
+ docs/res/dark.svg filter=lfs diff=lfs merge=lfs -text
85
+ docs/res/dev/devinst-1.png filter=lfs diff=lfs merge=lfs -text
86
+ docs/res/dev/devinst-11.png filter=lfs diff=lfs merge=lfs -text
87
+ docs/res/dev/devinst-12.png filter=lfs diff=lfs merge=lfs -text
88
+ docs/res/dev/devinst-13.png filter=lfs diff=lfs merge=lfs -text
89
+ docs/res/dev/devinst-14.png filter=lfs diff=lfs merge=lfs -text
90
+ docs/res/dev/devinst-3.png filter=lfs diff=lfs merge=lfs -text
91
+ docs/res/dev/devinst-4.png filter=lfs diff=lfs merge=lfs -text
92
+ docs/res/dev/devinst-5.png filter=lfs diff=lfs merge=lfs -text
93
+ docs/res/dev/devinst-6.png filter=lfs diff=lfs merge=lfs -text
94
+ docs/res/dev/devinst-7.png filter=lfs diff=lfs merge=lfs -text
95
+ docs/res/dev/devinst-8.png filter=lfs diff=lfs merge=lfs -text
96
+ docs/res/dev/devinst-9.png filter=lfs diff=lfs merge=lfs -text
97
+ docs/res/favicon.png filter=lfs diff=lfs merge=lfs -text
98
+ docs/res/favicon_round.png filter=lfs diff=lfs merge=lfs -text
99
+ docs/res/header.png filter=lfs diff=lfs merge=lfs -text
100
+ docs/res/install_guide.png filter=lfs diff=lfs merge=lfs -text
101
+ docs/res/profiles.png filter=lfs diff=lfs merge=lfs -text
102
+ docs/res/quickstart/image-24.png filter=lfs diff=lfs merge=lfs -text
103
+ docs/res/quickstart/ui_chat_management.png filter=lfs diff=lfs merge=lfs -text
104
+ docs/res/quickstart/ui_newchat1.png filter=lfs diff=lfs merge=lfs -text
105
+ docs/res/settings-page-ui1.png filter=lfs diff=lfs merge=lfs -text
106
+ docs/res/setup/1-docker-image-search.png filter=lfs diff=lfs merge=lfs -text
107
+ docs/res/setup/2-docker-image-run-3.png filter=lfs diff=lfs merge=lfs -text
108
+ docs/res/setup/2-docker-image-run.png filter=lfs diff=lfs merge=lfs -text
109
+ docs/res/setup/3-docker-port-mapping.png filter=lfs diff=lfs merge=lfs -text
110
+ docs/res/setup/4-docker-container-started.png filter=lfs diff=lfs merge=lfs -text
111
+ docs/res/setup/5-docker-click-to-open.png filter=lfs diff=lfs merge=lfs -text
112
+ docs/res/setup/6-docker-a0-running-new.png filter=lfs diff=lfs merge=lfs -text
113
+ docs/res/setup/9-rfc-devpage-on-docker-instance-1.png filter=lfs diff=lfs merge=lfs -text
114
+ docs/res/setup/9-rfc-devpage-on-local-sbs-1.png filter=lfs diff=lfs merge=lfs -text
115
+ docs/res/setup/a2a/a2a-conn.png filter=lfs diff=lfs merge=lfs -text
116
+ docs/res/setup/a2a/a2a2.png filter=lfs diff=lfs merge=lfs -text
117
+ docs/res/setup/docker-delete-image-1.png filter=lfs diff=lfs merge=lfs -text
118
+ docs/res/setup/image-1.png filter=lfs diff=lfs merge=lfs -text
119
+ docs/res/setup/image-10.png filter=lfs diff=lfs merge=lfs -text
120
+ docs/res/setup/image-11.png filter=lfs diff=lfs merge=lfs -text
121
+ docs/res/setup/image-12.png filter=lfs diff=lfs merge=lfs -text
122
+ docs/res/setup/image-13.png filter=lfs diff=lfs merge=lfs -text
123
+ docs/res/setup/image-14-u.png filter=lfs diff=lfs merge=lfs -text
124
+ docs/res/setup/image-14.png filter=lfs diff=lfs merge=lfs -text
125
+ docs/res/setup/image-15.png filter=lfs diff=lfs merge=lfs -text
126
+ docs/res/setup/image-16.png filter=lfs diff=lfs merge=lfs -text
127
+ docs/res/setup/image-17.png filter=lfs diff=lfs merge=lfs -text
128
+ docs/res/setup/image-18.png filter=lfs diff=lfs merge=lfs -text
129
+ docs/res/setup/image-2.png filter=lfs diff=lfs merge=lfs -text
130
+ docs/res/setup/image-20.png filter=lfs diff=lfs merge=lfs -text
131
+ docs/res/setup/image-21.png filter=lfs diff=lfs merge=lfs -text
132
+ docs/res/setup/image-22-1.png filter=lfs diff=lfs merge=lfs -text
133
+ docs/res/setup/image-23-1.png filter=lfs diff=lfs merge=lfs -text
134
+ docs/res/setup/image-3.png filter=lfs diff=lfs merge=lfs -text
135
+ docs/res/setup/image-4.png filter=lfs diff=lfs merge=lfs -text
136
+ docs/res/setup/image-5.png filter=lfs diff=lfs merge=lfs -text
137
+ docs/res/setup/image-6.png filter=lfs diff=lfs merge=lfs -text
138
+ docs/res/setup/image-7.png filter=lfs diff=lfs merge=lfs -text
139
+ docs/res/setup/image-8.png filter=lfs diff=lfs merge=lfs -text
140
+ docs/res/setup/image-9.png filter=lfs diff=lfs merge=lfs -text
141
+ docs/res/setup/image.png filter=lfs diff=lfs merge=lfs -text
142
+ docs/res/setup/macsocket.png filter=lfs diff=lfs merge=lfs -text
143
+ docs/res/setup/mcp/mcp-example-config.png filter=lfs diff=lfs merge=lfs -text
144
+ docs/res/setup/mcp/mcp-open-config.png filter=lfs diff=lfs merge=lfs -text
145
+ docs/res/setup/oses/apple.png filter=lfs diff=lfs merge=lfs -text
146
+ docs/res/setup/oses/linux.png filter=lfs diff=lfs merge=lfs -text
147
+ docs/res/setup/oses/windows.png filter=lfs diff=lfs merge=lfs -text
148
+ docs/res/setup/settings/1-agentConfig.png filter=lfs diff=lfs merge=lfs -text
149
+ docs/res/setup/settings/2-chat-model.png filter=lfs diff=lfs merge=lfs -text
150
+ docs/res/setup/settings/3-auth.png filter=lfs diff=lfs merge=lfs -text
151
+ docs/res/setup/settings/4-local-models.png filter=lfs diff=lfs merge=lfs -text
152
+ docs/res/setup/thumb_setup.png filter=lfs diff=lfs merge=lfs -text
153
+ docs/res/setup/update-initialize.png filter=lfs diff=lfs merge=lfs -text
154
+ docs/res/splash.webp filter=lfs diff=lfs merge=lfs -text
155
+ docs/res/splash_wide.png filter=lfs diff=lfs merge=lfs -text
156
+ docs/res/thumbnail-install.webp filter=lfs diff=lfs merge=lfs -text
157
+ docs/res/time-travel.png filter=lfs diff=lfs merge=lfs -text
158
+ docs/res/ui_screen2.png filter=lfs diff=lfs merge=lfs -text
159
+ docs/res/usage/a0-cli/a0-cli-browser-host-mode.png filter=lfs diff=lfs merge=lfs -text
160
+ docs/res/usage/a0-cli/a0-cli-browser-privacy.png filter=lfs diff=lfs merge=lfs -text
161
+ docs/res/usage/a0-cli/a0-cli-browser-status.png filter=lfs diff=lfs merge=lfs -text
162
+ docs/res/usage/a0-cli/a0-cli-command-browser.png filter=lfs diff=lfs merge=lfs -text
163
+ docs/res/usage/a0-cli/a0-cli-command-palette.png filter=lfs diff=lfs merge=lfs -text
164
+ docs/res/usage/a0-cli/a0-cli-host-picker.png filter=lfs diff=lfs merge=lfs -text
165
+ docs/res/usage/a0-cli/a0-cli-permissions.png filter=lfs diff=lfs merge=lfs -text
166
+ docs/res/usage/a0-cli/a0-cli-profile-created.png filter=lfs diff=lfs merge=lfs -text
167
+ docs/res/usage/a0-cli/a0-cli-profile-menu.png filter=lfs diff=lfs merge=lfs -text
168
+ docs/res/usage/a0-cli/a0-cli-start.png filter=lfs diff=lfs merge=lfs -text
169
+ docs/res/usage/action-btns.png filter=lfs diff=lfs merge=lfs -text
170
+ docs/res/usage/api-int/api-int-1.png filter=lfs diff=lfs merge=lfs -text
171
+ docs/res/usage/api-int/api-int-2image-gen-api2.png filter=lfs diff=lfs merge=lfs -text
172
+ docs/res/usage/api-int/api-int-3-api-key-missing-secrets.png filter=lfs diff=lfs merge=lfs -text
173
+ docs/res/usage/api-int/api-int-4-secrets-setting.png filter=lfs diff=lfs merge=lfs -text
174
+ docs/res/usage/api-int/api-int-5-finish.png filter=lfs diff=lfs merge=lfs -text
175
+ docs/res/usage/attachments-1.png filter=lfs diff=lfs merge=lfs -text
176
+ docs/res/usage/attachments-2.png filter=lfs diff=lfs merge=lfs -text
177
+ docs/res/usage/browser/browser-annotation-comment.png filter=lfs diff=lfs merge=lfs -text
178
+ docs/res/usage/browser/browser-canvas-example.png filter=lfs diff=lfs merge=lfs -text
179
+ docs/res/usage/browser/browser-canvas-wide.png filter=lfs diff=lfs merge=lfs -text
180
+ docs/res/usage/browser/browser-plugin-settings.png filter=lfs diff=lfs merge=lfs -text
181
+ docs/res/usage/browser/browser-tool-history-expanded.png filter=lfs diff=lfs merge=lfs -text
182
+ docs/res/usage/browser/browser-toolbar-settings.png filter=lfs diff=lfs merge=lfs -text
183
+ docs/res/usage/browser/host-browser-remote-debugging-allow.png filter=lfs diff=lfs merge=lfs -text
184
+ docs/res/usage/browser/host-browser-remote-debugging-setting.png filter=lfs diff=lfs merge=lfs -text
185
+ docs/res/usage/file-browser.png filter=lfs diff=lfs merge=lfs -text
186
+ docs/res/usage/file-edit.png filter=lfs diff=lfs merge=lfs -text
187
+ docs/res/usage/first-task.png filter=lfs diff=lfs merge=lfs -text
188
+ docs/res/usage/launcher/launcher-installs.png filter=lfs diff=lfs merge=lfs -text
189
+ docs/res/usage/launcher/launcher-runtime-setup.png filter=lfs diff=lfs merge=lfs -text
190
+ docs/res/usage/memory-dashboard.png filter=lfs diff=lfs merge=lfs -text
191
+ docs/res/usage/memory-editing.png filter=lfs diff=lfs merge=lfs -text
192
+ docs/res/usage/multi-agent.png filter=lfs diff=lfs merge=lfs -text
193
+ docs/res/usage/nudge.png filter=lfs diff=lfs merge=lfs -text
194
+ docs/res/usage/onboarding/onboarding-account-provider.png filter=lfs diff=lfs merge=lfs -text
195
+ docs/res/usage/onboarding/onboarding-agent-zero-api-key-model.png filter=lfs diff=lfs merge=lfs -text
196
+ docs/res/usage/onboarding/onboarding-agent-zero-api-model-dropdown.png filter=lfs diff=lfs merge=lfs -text
197
+ docs/res/usage/onboarding/onboarding-cloud-provider.png filter=lfs diff=lfs merge=lfs -text
198
+ docs/res/usage/onboarding/onboarding-local-ollama-main.png filter=lfs diff=lfs merge=lfs -text
199
+ docs/res/usage/onboarding/onboarding-model-gate.png filter=lfs diff=lfs merge=lfs -text
200
+ docs/res/usage/onboarding/onboarding-ready.png filter=lfs diff=lfs merge=lfs -text
201
+ docs/res/usage/onboarding/onboarding-start.png filter=lfs diff=lfs merge=lfs -text
202
+ docs/res/usage/onboarding/onboarding-utility-same-model.png filter=lfs diff=lfs merge=lfs -text
203
+ docs/res/usage/projects/projects-activate-project.png filter=lfs diff=lfs merge=lfs -text
204
+ docs/res/usage/projects/projects-creation.png filter=lfs diff=lfs merge=lfs -text
205
+ docs/res/usage/projects/projects-desc-and-instructions.png filter=lfs diff=lfs merge=lfs -text
206
+ docs/res/usage/projects/projects-first-ops.png filter=lfs diff=lfs merge=lfs -text
207
+ docs/res/usage/projects/projects-git-projects-tree.png filter=lfs diff=lfs merge=lfs -text
208
+ docs/res/usage/projects/projects-gitprojects-clone.png filter=lfs diff=lfs merge=lfs -text
209
+ docs/res/usage/restart.png filter=lfs diff=lfs merge=lfs -text
210
+ docs/res/usage/tasks/edit-task.png filter=lfs diff=lfs merge=lfs -text
211
+ docs/res/usage/tasks/scheduler-1.png filter=lfs diff=lfs merge=lfs -text
212
+ docs/res/usage/ui-context1.png filter=lfs diff=lfs merge=lfs -text
213
+ docs/res/usage/ui-history1.png filter=lfs diff=lfs merge=lfs -text
214
+ docs/res/usage/ui-katex-2.png filter=lfs diff=lfs merge=lfs -text
215
+ docs/res/usage/ui-settings-5-speech-to-text.png filter=lfs diff=lfs merge=lfs -text
216
+ docs/res/usage/ui-tts-stop-speech1.png filter=lfs diff=lfs merge=lfs -text
217
+ docs/res/usage/updating/self-update-v1-to-v2-warning.png filter=lfs diff=lfs merge=lfs -text
218
+ docs/res/usage/updating/self-update-v2-current.png filter=lfs diff=lfs merge=lfs -text
219
+ docs/res/usage/webui/agent-editor-advanced-prompts.png filter=lfs diff=lfs merge=lfs -text
220
+ docs/res/usage/webui/agent-editor-advanced-tools.png filter=lfs diff=lfs merge=lfs -text
221
+ docs/res/usage/webui/agent-editor-easy-permissions.png filter=lfs diff=lfs merge=lfs -text
222
+ docs/res/usage/webui/agent-editor-easy.png filter=lfs diff=lfs merge=lfs -text
223
+ docs/res/usage/webui/agent-editor-review.png filter=lfs diff=lfs merge=lfs -text
224
+ docs/res/usage/webui/agent-profile-manager.png filter=lfs diff=lfs merge=lfs -text
225
+ docs/res/usage/webui/agent-profile-selector.png filter=lfs diff=lfs merge=lfs -text
226
+ docs/res/usage/webui/chat-more-actions-skills.png filter=lfs diff=lfs merge=lfs -text
227
+ docs/res/usage/webui/dashboard.png filter=lfs diff=lfs merge=lfs -text
228
+ docs/res/usage/webui/desktop-canvas.png filter=lfs diff=lfs merge=lfs -text
229
+ docs/res/usage/webui/desktop-new-menu.png filter=lfs diff=lfs merge=lfs -text
230
+ docs/res/usage/webui/desktop-writer.png filter=lfs diff=lfs merge=lfs -text
231
+ docs/res/usage/webui/memory-dashboard-controls.png filter=lfs diff=lfs merge=lfs -text
232
+ docs/res/usage/webui/model-preset-selector.png filter=lfs diff=lfs merge=lfs -text
233
+ 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
docker/base/Dockerfile CHANGED
@@ -1,40 +1,3 @@
1
- # Use the latest slim version of Kali Linux
2
- FROM kalilinux/kali-rolling
3
-
4
-
5
- # Set locale to en_US.UTF-8 and timezone to UTC
6
- RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y locales tzdata
7
- RUN sed -i -e 's/# \(en_US\.UTF-8 .*\)/\1/' /etc/locale.gen && \
8
- dpkg-reconfigure --frontend=noninteractive locales && \
9
- update-locale LANG=en_US.UTF-8 LANGUAGE=en_US:en LC_ALL=en_US.UTF-8
10
- RUN ln -sf /usr/share/zoneinfo/UTC /etc/localtime
11
- RUN echo "UTC" > /etc/timezone
12
- RUN dpkg-reconfigure -f noninteractive tzdata
13
- ENV LANG=en_US.UTF-8
14
- ENV LANGUAGE=en_US:en
15
- ENV LC_ALL=en_US.UTF-8
16
- ENV TZ=UTC
17
-
18
- # Copy contents of the project to /
19
- COPY ./fs/ /
20
-
21
- # install packages software (split for better cache management)
22
- RUN bash /ins/install_base_packages1.sh
23
- RUN bash /ins/install_base_packages2.sh
24
- RUN bash /ins/install_base_packages3.sh
25
- RUN bash /ins/install_base_packages4.sh
26
-
27
- # install python after packages to ensure version overriding
28
- RUN bash /ins/install_python.sh
29
-
30
- # install searxng
31
- RUN bash /ins/install_searxng.sh
32
-
33
- # configure ssh
34
- RUN bash /ins/configure_ssh.sh
35
-
36
- # after install
37
- RUN bash /ins/after_install.sh
38
-
39
- # Keep container running infinitely
40
- CMD ["tail", "-f", "/dev/null"]
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:234bdf6caffd5a7ddac176efea5b3060f1de4d38f26790277876370304b05034
3
+ size 1196
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
docker/base/build.txt CHANGED
@@ -1,18 +1,3 @@
1
- # local image with smart cache
2
- docker build -t agent-zero-base:local --build-arg CACHE_DATE=$(date +%Y-%m-%d:%H:%M:%S) .
3
-
4
- # local image without cache
5
- docker build -t agent-zero-base:local --no-cache .
6
-
7
- # dockerhub push:
8
-
9
- docker login
10
-
11
- # with cache
12
- docker buildx build -t agent0ai/agent-zero-base:latest --platform linux/amd64,linux/arm64 --push --build-arg CACHE_DATE=$(date +%Y-%m-%d:%H:%M:%S) .
13
-
14
- # without cache
15
- docker buildx build -t agent0ai/agent-zero-base:latest --platform linux/amd64,linux/arm64 --push --build-arg CACHE_DATE=$(date +%Y-%m-%d:%H:%M:%S) --no-cache .
16
-
17
- # plain output
18
- --progress=plain
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:7e6132c3b52e84a646dfc752ccea6a278c01ef1f6b1c7d20a217496cb0dda743
3
+ size 608
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
docker/base/fs/etc/searxng/limiter.toml CHANGED
@@ -1,33 +1,3 @@
1
- [botdetection]
2
- # Number of values to trust for X-Forwarded-For.
3
- trusted_proxies = ["127.0.0.1"]
4
-
5
- # The prefix defines the number of leading bits in an address that are compared
6
- # to determine whether or not an address is part of a (client) network.
7
- ipv4_prefix = 32
8
- ipv6_prefix = 48
9
-
10
- [botdetection.ip_limit]
11
- # To get unlimited access in a local network, by default link-local addresses
12
- # (networks) are not monitored by the ip_limit
13
- filter_link_local = false
14
-
15
- # Activate link_token method in the ip_limit method
16
- link_token = false
17
-
18
- [botdetection.ip_lists]
19
- # In the limiter, the ip_lists method has priority over all other methods.
20
- # If an IP is in the pass_ip list, it has unrestricted access and is not
21
- # checked if, for example, the "user agent" suggests a bot (e.g., curl).
22
- block_ip = [
23
- # '93.184.216.34', # Example IPv4 address
24
- # '257.1.1.1', # Invalid IP --> will be ignored, logged in ERROR class
25
- ]
26
- pass_ip = [
27
- # '192.168.0.0/16', # IPv4 private network
28
- # 'fe80::/10', # IPv6 link-local; overrides botdetection.ip_limit.filter_link_local
29
- ]
30
-
31
- # Activate passlist of (hardcoded) IPs from the SearXNG organization,
32
- # e.g., `check.searx.space`.
33
- pass_searxng_org = true
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:0823d3680c926766580465b06b07ffb2198c9e4e53ca56a2ca3a45fc4a5811be
3
+ size 1199
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
docker/base/fs/etc/searxng/settings.yml CHANGED
@@ -1,91 +1,3 @@
1
- # SearXNG settings
2
-
3
- # Keep a minimal default engine set. Wikidata currently returns
4
- # variant payloads that break the 2026.04 searxng bootstrap init path.
5
- use_default_settings:
6
- engines:
7
- remove:
8
- - wikidata
9
-
10
- general:
11
- debug: false
12
- instance_name: "SearXNG"
13
-
14
- search:
15
- safe_search: 0
16
- # autocomplete: 'duckduckgo'
17
- formats:
18
- - json
19
- # - html
20
-
21
- server:
22
- # Is overwritten by ${SEARXNG_SECRET}
23
- secret_key: "dummy"
24
- port: 55510
25
- limiter: false
26
- image_proxy: false
27
- # public URL of the instance, to ensure correct inbound links. Is overwritten
28
- # by ${SEARXNG_URL}.
29
- # base_url: http://example.com/location
30
-
31
- # redis:
32
- # # URL to connect redis database. Is overwritten by ${SEARXNG_REDIS_URL}.
33
- # url: unix:///usr/local/searxng-redis/run/redis.sock?db=0
34
-
35
- ui:
36
- static_use_hash: true
37
-
38
- # preferences:
39
- # lock:
40
- # - autocomplete
41
- # - method
42
-
43
- enabled_plugins:
44
- - 'Hash plugin'
45
- - 'Self Informations'
46
- - 'Tracker URL remover'
47
- # - 'Ahmia blacklist'
48
- # - 'Hostnames plugin' # see 'hostnames' configuration below
49
- # - 'Open Access DOI rewrite'
50
-
51
- # plugins:
52
- # - only_show_green_results
53
-
54
- # hostnames:
55
- # replace:
56
- # '(.*\.)?youtube\.com$': 'invidious.example.com'
57
- # '(.*\.)?youtu\.be$': 'invidious.example.com'
58
- # remove:
59
- # - '(.*\.)?facebook.com$'
60
- # low_priority:
61
- # - '(.*\.)?google\.com$'
62
- # high_priority:
63
- # - '(.*\.)?wikipedia.org$'
64
-
65
- engines:
66
-
67
- - name: ahmia
68
- disabled: true
69
- inactive: true
70
-
71
- - name: torch
72
- disabled: true
73
- inactive: true
74
-
75
- # - name: fdroid
76
- # disabled: false
77
- #
78
- # - name: apk mirror
79
- # disabled: false
80
- #
81
- # - name: mediathekviewweb
82
- # categories: TV
83
- # disabled: false
84
- #
85
- # - name: invidious
86
- # disabled: false
87
- # base_url:
88
- # - https://invidious.snopyta.org
89
- # - https://invidious.tiekoetter.com
90
- # - https://invidio.xamh.de
91
- # - https://inv.riverside.rocks
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:285a75924555f7ce3e2c31020eb0ea48d9d86cdaae5488b4eedf07b0d3006d89
3
+ size 1890
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
docker/base/fs/ins/after_install.sh CHANGED
@@ -1,5 +1,3 @@
1
- #!/bin/bash
2
- set -e
3
-
4
- # clean up apt cache
5
- sudo apt-get clean
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:307cbee5297787e5f380cd77003e559f66e5f18aa88e8dc8ea07c94971ad7af5
3
+ size 60
 
 
docker/base/fs/ins/configure_ssh.sh CHANGED
@@ -1,6 +1,3 @@
1
- #!/bin/bash
2
- set -e
3
-
4
- # Set up SSH
5
- mkdir -p /var/run/sshd && \
6
- sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:16e50ddfdac1068376d23490242d51cfbad1297a3a686b2c70fbebe54b5c95d8
3
+ size 152
 
 
 
docker/base/fs/ins/install_base_packages1.sh CHANGED
@@ -1,11 +1,3 @@
1
- #!/bin/bash
2
- set -e
3
-
4
- echo "====================BASE PACKAGES1 START===================="
5
-
6
- apt-get update && apt-get upgrade -y
7
-
8
- apt-get install -y --no-install-recommends \
9
- sudo curl wget git cron unzip 7zip
10
-
11
- echo "====================BASE PACKAGES1 END===================="
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:a8fdbbaf67375fd8ce6691a7e5dafef875649687b8355ab3c4f9fefbb4cdb1ca
3
+ size 278
 
 
 
 
 
 
 
 
docker/base/fs/ins/install_base_packages2.sh CHANGED
@@ -1,10 +1,3 @@
1
- #!/bin/bash
2
- set -e
3
-
4
- echo "====================BASE PACKAGES2 START===================="
5
-
6
-
7
- apt-get install -y --no-install-recommends \
8
- openssh-server ffmpeg supervisor
9
-
10
- echo "====================BASE PACKAGES2 END===================="
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:91b5a734921d9be8fe70705f9d8a1c6ce731ef718b8bfb1cd92d5133498a4c59
3
+ size 239
 
 
 
 
 
 
 
docker/base/fs/ins/install_base_packages3.sh CHANGED
@@ -1,13 +1,3 @@
1
- #!/bin/bash
2
- set -e
3
-
4
- echo "====================BASE PACKAGES3 START===================="
5
-
6
- apt-get install -y --no-install-recommends \
7
- nodejs npm
8
-
9
- echo "====================BASE PACKAGES3 NPM===================="
10
-
11
- # we shall not install npx separately, it's discontinued and some versions are broken
12
- # npm i -g npx
13
- echo "====================BASE PACKAGES3 END===================="
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:964b5a3d7f2afdaf2e27bf60bb28e77b6bcc8d19476722615d47254529e352c7
3
+ size 384
 
 
 
 
 
 
 
 
 
 
docker/base/fs/ins/install_base_packages4.sh CHANGED
@@ -1,9 +1,3 @@
1
- #!/bin/bash
2
- set -e
3
-
4
- echo "====================BASE PACKAGES4 START===================="
5
-
6
- apt-get install -y --no-install-recommends \
7
- tesseract-ocr tesseract-ocr-script-latn poppler-utils
8
-
9
- echo "====================BASE PACKAGES4 END===================="
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:2d7ac6e3c9ed2b10e886ef56de073e35643981181e1f9b77b22e9541d771b7ce
3
+ size 258
 
 
 
 
 
 
docker/base/fs/ins/install_python.sh CHANGED
@@ -1,73 +1,3 @@
1
- #!/bin/bash
2
- set -e
3
-
4
- echo "====================PYTHON START===================="
5
-
6
- echo "====================PYTHON 3.13===================="
7
-
8
- apt clean && apt-get update && apt-get -y upgrade
9
-
10
- # install python 3.13 globally
11
- apt-get install -y --no-install-recommends \
12
- python3.13 python3.13-venv
13
- #python3.13-dev
14
-
15
-
16
- echo "====================PYTHON 3.13 VENV===================="
17
-
18
- # create and activate default venv
19
- python3.13 -m venv /opt/venv
20
- source /opt/venv/bin/activate
21
-
22
- # upgrade pip and install static packages
23
- pip install --no-cache-dir --upgrade pip pipx ipython requests
24
-
25
- echo "====================PYTHON PYVENV===================="
26
-
27
- # Install pyenv build dependencies.
28
- apt-get install -y --no-install-recommends \
29
- make build-essential libssl-dev zlib1g-dev libbz2-dev \
30
- libreadline-dev libsqlite3-dev wget curl llvm \
31
- libncursesw5-dev xz-utils tk-dev libxml2-dev \
32
- libxmlsec1-dev libffi-dev liblzma-dev
33
-
34
- # Install pyenv globally
35
- git clone https://github.com/pyenv/pyenv.git /opt/pyenv
36
-
37
- # Setup environment variables for pyenv to be available system-wide
38
- cat > /etc/profile.d/pyenv.sh <<'EOF'
39
- export PYENV_ROOT="/opt/pyenv"
40
- export PATH="$PYENV_ROOT/bin:$PATH"
41
- eval "$(pyenv init --path)"
42
- EOF
43
-
44
- # fix permissions
45
- chmod +x /etc/profile.d/pyenv.sh
46
-
47
- # Source pyenv environment to make it available in this script
48
- source /etc/profile.d/pyenv.sh
49
-
50
- # Install Python 3.12.4
51
- echo "====================PYENV 3.12 VENV===================="
52
- pyenv install 3.12.4
53
-
54
- /opt/pyenv/versions/3.12.4/bin/python -m venv /opt/venv-a0
55
- source /opt/venv-a0/bin/activate
56
-
57
- # upgrade pip and install static packages
58
- pip install --no-cache-dir --upgrade pip pipx
59
-
60
- # Install some packages in specific variants
61
- pip install --no-cache-dir \
62
- torch==2.4.0 \
63
- torchvision==0.19.0 \
64
- --index-url https://download.pytorch.org/whl/cpu
65
-
66
- echo "====================PYTHON UV ===================="
67
-
68
- curl -Ls https://astral.sh/uv/install.sh | UV_INSTALL_DIR=/usr/local/bin sh
69
-
70
- # clean up pip cache
71
- pip cache purge
72
-
73
- echo "====================PYTHON END===================="
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:9c83793cf9f40cc2f1c318e3014f53b540e1056954eba409bc13712b0fc8579d
3
+ size 2068
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
docker/base/fs/ins/install_searxng.sh CHANGED
@@ -1,29 +1,3 @@
1
- #!/bin/bash
2
- set -e
3
-
4
- echo "====================SEARXNG1 START===================="
5
-
6
- # Install necessary packages
7
- apt-get install -y \
8
- git build-essential libxslt-dev zlib1g-dev libffi-dev libssl-dev
9
- # python3.12-babel uwsgi uwsgi-plugin-python3
10
-
11
-
12
- # Add the searxng system user
13
- useradd --shell /bin/bash --system \
14
- --home-dir "/usr/local/searxng" \
15
- --comment 'Privacy-respecting metasearch engine' \
16
- searxng
17
-
18
- # Add the searxng user to the sudo group
19
- usermod -aG sudo searxng
20
-
21
- # Create the searxng directory and set ownership
22
- mkdir "/usr/local/searxng"
23
- chown -R "searxng:searxng" "/usr/local/searxng"
24
-
25
- echo "====================SEARXNG1 END===================="
26
-
27
- # Start a new shell as the searxng user and run the installation script
28
- su - searxng -c "bash /ins/install_searxng2.sh"
29
-
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:b9fdb44b3ed98908f44fdc0dda73946afe22a12e56067863da837bfefc528b8e
3
+ size 800
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
docker/base/fs/ins/install_searxng2.sh CHANGED
@@ -1,36 +1,3 @@
1
- #!/bin/bash
2
- set -e
3
-
4
- echo "====================SEARXNG2 START===================="
5
-
6
-
7
- # clone SearXNG repo
8
- git clone "https://github.com/searxng/searxng" \
9
- "/usr/local/searxng/searxng-src"
10
-
11
- echo "====================SEARXNG2 VENV===================="
12
-
13
- # create virtualenv:
14
- python3.13 -m venv "/usr/local/searxng/searx-pyenv"
15
-
16
- # make it default
17
- echo ". /usr/local/searxng/searx-pyenv/bin/activate" \
18
- >> "/usr/local/searxng/.profile"
19
-
20
- # activate venv
21
- source "/usr/local/searxng/searx-pyenv/bin/activate"
22
-
23
- echo "====================SEARXNG2 INST===================="
24
-
25
- # update pip's boilerplate
26
- pip install --no-cache-dir -U pip setuptools wheel pyyaml lxml msgspec typing_extensions
27
-
28
- # jump to SearXNG's working tree and install SearXNG into virtualenv
29
- cd "/usr/local/searxng/searxng-src"
30
- # pip install --no-cache-dir --use-pep517 --no-build-isolation -e .
31
- pip install --no-cache-dir --use-pep517 --no-build-isolation .
32
-
33
- # cleanup cache
34
- pip cache purge
35
-
36
- echo "====================SEARXNG2 END===================="
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:ea486499849de2f7bc02febb8cac390b94d01e10dcdf3415f9b126c5f1be6726
3
+ size 1048
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
docker/run/AGENTS.md CHANGED
@@ -1,43 +1,3 @@
1
- # Docker Runtime Image DOX
2
-
3
- ## Purpose
4
-
5
- - Own the runnable Agent Zero image context and local compose example.
6
- - Install Agent Zero from a selected branch onto the base image and prepare runtime entrypoints.
7
-
8
- ## Ownership
9
-
10
- - `Dockerfile` owns branch-based image assembly, exposed ports, and container startup command.
11
- - `docker-compose.yml` owns the local compose service example.
12
- - `build.txt` owns maintainer build and push command notes.
13
- - `fs/exe/` owns runtime entrypoint, supervisor, self-update, Node eval, and service scripts.
14
- - `fs/exe/huggingface-entrypoint.sh` owns Space-specific startup defaults, including disabling outbound Cloudflare tunnels and enabling A2A.
15
- - `fs/ins/` owns preinstall, installation, virtualenv, Playwright, SSH, and postinstall scripts.
16
- - Files under `fs/` are copied to container root during the runtime build.
17
-
18
- ## Local Contracts
19
-
20
- - `BRANCH` is required for branch-based Docker builds.
21
- - Preserve exposed ports for SSH, HTTP, and tunneled services unless docs and workflows are updated together.
22
- - Keep the two-runtime Python model aligned with the root contract.
23
- - Keep runtime desktop packages on `kali-last-snapshot`; carry the rolling base's matching ATK introspection package into that transaction, then pin the verified Python 3.13-compatible LibreOffice and complete Xpra runtime versions in `fs/ins/install_additional.sh` for both published architectures.
24
- - Do not bake secrets, local `.env` values, or user data into the image.
25
- - Runtime startup must ensure `/a0/usr/uploads` exists before supervised services start.
26
- - Runtime startup raises the soft open-file limit toward `A0_NOFILE_LIMIT` (default `65535`) before supervisord starts, bounded by the container hard limit.
27
- - Self-update user-data backups skip Time Travel shadow history under `usr/.time_travel/` and transient Desktop agent state.
28
- - Self-update waits up to 180 seconds for the updated or restored WebUI health check by default; `A0_SELF_UPDATE_HEALTH_TIMEOUT_SECONDS` may override it.
29
- - Successful or already-current self-updates refresh an installed Codex CLI with npm on a best-effort basis; missing CLIs and registry failures must not block Agent Zero startup.
30
-
31
- ## Work Guidance
32
-
33
- - Keep startup scripts explicit about framework runtime versus execution runtime.
34
- - Coordinate tag, branch, and publishing changes with GitHub workflow automation.
35
-
36
- ## Verification
37
-
38
- - Build `docker/run` when changing Dockerfile or install scripts.
39
- - Smoke-test container startup after entrypoint, supervisor, port, or compose changes.
40
-
41
- ## Child DOX Index
42
-
43
- No child DOX files.
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:17bbe98c21959fe36a5b7fe507d326495d066b9cd55358e6244b65c9b375ec6f
3
+ size 2574
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
docker/run/Dockerfile CHANGED
@@ -1,36 +1,3 @@
1
- # Use the pre-built base image for A0
2
- # FROM agent-zero-base:local
3
- # FROM agent0ai/agent-zero-base:testing
4
- FROM agent0ai/agent-zero-base:latest
5
-
6
- # Check if the argument is provided, else throw an error
7
- ARG BRANCH
8
- RUN if [ -z "$BRANCH" ]; then echo "ERROR: BRANCH is not set!" >&2; exit 1; fi
9
- ENV BRANCH=$BRANCH
10
-
11
- # Copy filesystem files to root
12
- COPY ./fs/ /
13
-
14
- # pre installation steps
15
- RUN bash /ins/pre_install.sh $BRANCH
16
-
17
- # install A0
18
- RUN bash /ins/install_A0.sh $BRANCH
19
-
20
- # install additional software
21
- RUN bash /ins/install_additional.sh $BRANCH
22
-
23
- # cleanup repo and install A0 without caching, this speeds up builds
24
- ARG CACHE_DATE=none
25
- RUN echo "cache buster $CACHE_DATE" && bash /ins/install_A02.sh $BRANCH
26
-
27
- # post installation steps
28
- RUN bash /ins/post_install.sh $BRANCH
29
-
30
- # Expose ports
31
- EXPOSE 22 80 9000-9009
32
-
33
- RUN chmod +x /exe/initialize.sh /exe/run_A0.sh /exe/run_searxng.sh /exe/run_tunnel_api.sh /exe/trigger_self_update.sh
34
-
35
- # initialize runtime and switch to supervisord
36
- CMD ["/exe/initialize.sh", "$BRANCH"]
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:e3ae715c51dbf449efa619d79149742eb9bae802d722a75b8476b0a32ba3e8dd
3
+ size 1016
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
docker/run/build.txt CHANGED
@@ -1,42 +1,3 @@
1
-
2
- # LOCAL BUILDS
3
- # Run these commands from the project root folder
4
-
5
- # local development image based on local files with smart cache
6
- docker build -f DockerfileLocal -t agent-zero-local --build-arg CACHE_DATE=$(date +%Y-%m-%d:%H:%M:%S) .
7
-
8
- # local development image based on local files without cache
9
- docker build -f DockerfileLocal -t agent-zero-local --no-cache .
10
-
11
-
12
- # GIT BASED BUILDS
13
- # Run these commands from the /docker/run directory
14
-
15
- # local image based on development branch instead of local files
16
- docker build -t agent-zero-development --build-arg BRANCH=development --build-arg CACHE_DATE=$(date +%Y-%m-%d:%H:%M:%S) .
17
-
18
- # local image based on testing branch instead of local files
19
- docker build -t agent-zero-testing --build-arg BRANCH=testing --build-arg CACHE_DATE=$(date +%Y-%m-%d:%H:%M:%S) .
20
-
21
- # local image based on main branch instead of local files
22
- docker build -t agent-zero-main --build-arg BRANCH=main --build-arg CACHE_DATE=$(date +%Y-%m-%d:%H:%M:%S) .
23
-
24
-
25
-
26
- # DOCKERHUB PUSH
27
- # Run these commands from the /docker/run directory
28
-
29
- docker login
30
-
31
- # development:
32
- docker buildx build -t agent0ai/agent-zero:development --platform linux/amd64,linux/arm64 --push --build-arg BRANCH=development --build-arg CACHE_DATE=$(date +%Y-%m-%d:%H:%M:%S) .
33
-
34
- # testing:
35
- docker buildx build -t agent0ai/agent-zero:testing --platform linux/amd64,linux/arm64 --push --build-arg BRANCH=testing --build-arg CACHE_DATE=$(date +%Y-%m-%d:%H:%M:%S) .
36
-
37
- # main
38
- docker buildx build -t agent0ai/agent-zero:vx.x.x -t agent0ai/agent-zero:latest --platform linux/amd64,linux/arm64 --push --build-arg BRANCH=main --build-arg CACHE_DATE=$(date +%Y-%m-%d:%H:%M:%S) .
39
-
40
-
41
- # plain output
42
- --progress=plain
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:75dc51ca78f49f9860ab89813aedc3d37d7f7003863b465a6c02655729c25ae0
3
+ size 1671
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
docker/run/docker-compose.yml CHANGED
@@ -1,14 +1,3 @@
1
- services:
2
- agent-zero:
3
- container_name: agent-zero
4
- image: agent0ai/agent-zero:latest
5
- volumes:
6
- - ./agent-zero:/a0
7
- ports:
8
- - "50080:80"
9
- ulimits:
10
- nofile:
11
- soft: 65535
12
- hard: 65535
13
- extra_hosts:
14
- - "host.docker.internal:host-gateway"
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:a7d6aec3bf1bc9e292ccf8f1dafe513bfb869d5093244cad97b8441375edeca6
3
+ size 289
 
 
 
 
 
 
 
 
 
 
 
docker/run/fs/etc/nginx/nginx.conf CHANGED
@@ -1,31 +1,3 @@
1
- daemon off;
2
- worker_processes 2;
3
- user www-data;
4
-
5
- events {
6
- use epoll;
7
- worker_connections 128;
8
- }
9
-
10
- error_log /var/log/nginx/error.log info;
11
-
12
- http {
13
- server_tokens off;
14
- include mime.types;
15
- charset utf-8;
16
-
17
- access_log /var/log/nginx/access.log combined;
18
-
19
- server {
20
- server_name 127.0.0.1:31735;
21
- listen 127.0.0.1:31735;
22
-
23
- error_page 500 502 503 504 /50x.html;
24
-
25
- location / {
26
- root /;
27
- }
28
-
29
- }
30
-
31
- }
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:f9e58e00c90a7bbe25c26087c7c52ff49dcdbedce331cc4ac24f980104743337
3
+ size 545
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
docker/run/fs/etc/searxng/limiter.toml CHANGED
@@ -1,33 +1,3 @@
1
- [botdetection]
2
- # Number of values to trust for X-Forwarded-For.
3
- trusted_proxies = ["127.0.0.1"]
4
-
5
- # The prefix defines the number of leading bits in an address that are compared
6
- # to determine whether or not an address is part of a (client) network.
7
- ipv4_prefix = 32
8
- ipv6_prefix = 48
9
-
10
- [botdetection.ip_limit]
11
- # To get unlimited access in a local network, by default link-local addresses
12
- # (networks) are not monitored by the ip_limit
13
- filter_link_local = false
14
-
15
- # Activate link_token method in the ip_limit method
16
- link_token = false
17
-
18
- [botdetection.ip_lists]
19
- # In the limiter, the ip_lists method has priority over all other methods.
20
- # If an IP is in the pass_ip list, it has unrestricted access and is not
21
- # checked if, for example, the "user agent" suggests a bot (e.g., curl).
22
- block_ip = [
23
- # '93.184.216.34', # Example IPv4 address
24
- # '257.1.1.1', # Invalid IP --> will be ignored, logged in ERROR class
25
- ]
26
- pass_ip = [
27
- # '192.168.0.0/16', # IPv4 private network
28
- # 'fe80::/10', # IPv6 link-local; overrides botdetection.ip_limit.filter_link_local
29
- ]
30
-
31
- # Activate passlist of (hardcoded) IPs from the SearXNG organization,
32
- # e.g., `check.searx.space`.
33
- pass_searxng_org = true
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:0823d3680c926766580465b06b07ffb2198c9e4e53ca56a2ca3a45fc4a5811be
3
+ size 1199
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
docker/run/fs/etc/searxng/settings.yml CHANGED
@@ -1,98 +1,3 @@
1
- # SearXNG settings
2
-
3
- use_default_settings:
4
- engines:
5
- remove:
6
- - radio browser
7
- - wikidata
8
- # TODO enable radio_browser when it works again
9
- # currently it crashes on x86 on gethostbyaddr
10
-
11
- general:
12
- debug: false
13
- instance_name: "SearXNG"
14
-
15
- search:
16
- safe_search: 0
17
- # autocomplete: 'duckduckgo'
18
- formats:
19
- - json
20
- # - html
21
-
22
- server:
23
- # Is overwritten by ${SEARXNG_SECRET}
24
- secret_key: "dummy"
25
- port: 55510
26
- limiter: false
27
- image_proxy: false
28
- # public URL of the instance, to ensure correct inbound links. Is overwritten
29
- # by ${SEARXNG_URL}.
30
- # base_url: http://example.com/location
31
-
32
- # redis:
33
- # # URL to connect redis database. Is overwritten by ${SEARXNG_REDIS_URL}.
34
- # url: unix:///usr/local/searxng-redis/run/redis.sock?db=0
35
-
36
- ui:
37
- static_use_hash: true
38
-
39
- # preferences:
40
- # lock:
41
- # - autocomplete
42
- # - method
43
-
44
- enabled_plugins:
45
- - 'Hash plugin'
46
- - 'Self Informations'
47
- - 'Tracker URL remover'
48
- # - 'Ahmia blacklist'
49
- # - 'Hostnames plugin' # see 'hostnames' configuration below
50
- # - 'Open Access DOI rewrite'
51
-
52
- # plugins:
53
- # - only_show_green_results
54
-
55
- # hostnames:
56
- # replace:
57
- # '(.*\.)?youtube\.com$': 'invidious.example.com'
58
- # '(.*\.)?youtu\.be$': 'invidious.example.com'
59
- # remove:
60
- # - '(.*\.)?facebook.com$'
61
- # low_priority:
62
- # - '(.*\.)?google\.com$'
63
- # high_priority:
64
- # - '(.*\.)?wikipedia.org$'
65
-
66
- engines:
67
- - name: radio browser
68
- engine: radio_browser
69
- disabled: true
70
- inactive: true
71
-
72
- - name: ahmia
73
- disabled: true
74
- inactive: true
75
-
76
- - name: torch
77
- disabled: true
78
- inactive: true
79
- # TODO enable radio_browser when it works again
80
- # currently it crashes on x86 on gethostbyaddr
81
-
82
- # - name: fdroid
83
- # disabled: false
84
- #
85
- # - name: apk mirror
86
- # disabled: false
87
- #
88
- # - name: mediathekviewweb
89
- # categories: TV
90
- # disabled: false
91
- #
92
- # - name: invidious
93
- # disabled: false
94
- # base_url:
95
- # - https://invidious.snopyta.org
96
- # - https://invidious.tiekoetter.com
97
- # - https://invidio.xamh.de
98
- # - https://inv.riverside.rocks
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:b06e7385e5a7a2e2daad711852551cd82c3c2d7923c1cd5d55ddd085e7a04fad
3
+ size 2055
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
docker/run/fs/etc/supervisor/conf.d/supervisord.conf CHANGED
@@ -1,95 +1,3 @@
1
- [supervisord]
2
- nodaemon=true
3
- user=root
4
- logfile=/dev/stdout
5
- logfile_maxbytes=0
6
- pidfile=/var/run/supervisord.pid
7
- exitcodes=0,2
8
- directory=/
9
-
10
- [unix_http_server]
11
- file=/var/run/supervisor.sock
12
- chmod=0777
13
-
14
- [rpcinterface:supervisor]
15
- supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
16
-
17
- [supervisorctl]
18
- serverurl=unix:///var/run/supervisor.sock
19
-
20
- [program:run_sshd]
21
- command=/usr/sbin/sshd -D
22
- environment=
23
- stopwaitsecs=1
24
- stdout_logfile=/dev/stdout
25
- stdout_logfile_maxbytes=0
26
- stderr_logfile=/dev/stderr
27
- stderr_logfile_maxbytes=0
28
- autorestart=true
29
- startretries=3
30
- stopasgroup=true
31
- killasgroup=true
32
-
33
- [program:run_cron]
34
- command=/usr/sbin/cron -f
35
- environment=
36
- stopwaitsecs=1
37
- stdout_logfile=/dev/stdout
38
- stdout_logfile_maxbytes=0
39
- stderr_logfile=/dev/stderr
40
- stderr_logfile_maxbytes=0
41
- autorestart=true
42
- startretries=3
43
- stopasgroup=true
44
- killasgroup=true
45
-
46
- [program:run_searxng]
47
- command=/exe/run_searxng.sh
48
- environment=SEARXNG_SETTINGS_PATH=/etc/searxng/settings.yml
49
- user=searxng
50
- directory=/usr/local/searxng/searxng-src
51
- stopwaitsecs=1
52
- stdout_logfile=/dev/stdout
53
- stdout_logfile_maxbytes=0
54
- stderr_logfile=/dev/stderr
55
- stderr_logfile_maxbytes=0
56
- autorestart=true
57
- startretries=3
58
- stopasgroup=true
59
- killasgroup=true
60
-
61
- [program:run_ui]
62
- command=/exe/run_A0.sh
63
- environment=
64
- user=root
65
- stopwaitsecs=60
66
- stdout_logfile=/dev/stdout
67
- stdout_logfile_maxbytes=0
68
- stderr_logfile=/dev/stderr
69
- stderr_logfile_maxbytes=0
70
- autorestart=true
71
- startretries=3
72
- stopasgroup=true
73
- killasgroup=true
74
-
75
- [program:run_tunnel_api]
76
- command=/exe/run_tunnel_api.sh
77
- environment=
78
- user=root
79
- stopwaitsecs=60
80
- stdout_logfile=/dev/stdout
81
- stdout_logfile_maxbytes=0
82
- stderr_logfile=/dev/stderr
83
- stderr_logfile_maxbytes=0
84
- autorestart=true
85
- startretries=3
86
- stopasgroup=true
87
- killasgroup=true
88
-
89
- [eventlistener:the_listener]
90
- command=python3 /exe/supervisor_event_listener.py
91
- events=PROCESS_STATE_FATAL
92
- stdout_logfile=/dev/stdout
93
- stdout_logfile_maxbytes=0
94
- stderr_logfile=/dev/stderr
95
- stderr_logfile_maxbytes=0
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:056f6fddc74b8dae60f17e99049605871faf6b1722b199447bd159d156663dd3
3
+ size 1941
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
docker/run/fs/exe/huggingface-entrypoint.sh CHANGED
@@ -1,42 +1,3 @@
1
- #!/bin/bash
2
- set -euo pipefail
3
-
4
- # Hugging Face provides the public HTTPS edge; never start an outbound tunnel.
5
- if [ "${A0_CLOUDFLARE_DISABLED:-true}" != "true" ]; then
6
- echo "A0_CLOUDFLARE_DISABLED must remain true on Hugging Face Spaces." >&2
7
- exit 1
8
- fi
9
-
10
- mkdir -p /a0/usr
11
-
12
- # Settings normalization fills all other defaults. This deployment default makes
13
- # the authenticated A2A endpoint available immediately after the Space starts.
14
- python3 - <<'PY'
15
- import json
16
- import os
17
- from pathlib import Path
18
-
19
- settings_path = Path("/a0/usr/settings.json")
20
- try:
21
- settings = json.loads(settings_path.read_text(encoding="utf-8"))
22
- except (FileNotFoundError, json.JSONDecodeError):
23
- settings = {}
24
-
25
- settings["a2a_server_enabled"] = True
26
- if api_key := os.environ.get("SPYNEL_AGENT_ZERO_API_KEY", "").strip():
27
- # Use one secret for the loopback client and the existing API-key verifier.
28
- # It is persisted in the private runtime settings file and never printed.
29
- settings["mcp_server_token"] = api_key
30
- settings_path.write_text(json.dumps(settings, indent=2) + "\n", encoding="utf-8")
31
- PY
32
-
33
- echo "Space URL: ${A0_PUBLIC_URL:-https://leon4gr45-agent.hf.space}"
34
- echo "A2A enabled at /a2a; authenticated incoming API enabled at /api_message."
35
- echo "Starting Agent Zero as uid=$(id -u) on ${WEB_UI_HOST:-0.0.0.0}:${WEB_UI_PORT:-7860}."
36
-
37
- # The general Docker initializer is intentionally not used in a Space: it starts
38
- # privileged SSH/cron/supervisor services and inherited images may include
39
- # password initialization. Space dependencies and model data are installed at
40
- # image-build time, so runtime package installation is disabled by the image.
41
- cd /a0
42
- exec /opt/venv-a0/bin/python run_ui.py
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:f23cde5677afd1c14ea00d92d8c827198d6b18adb3b70f967875d2577396a126
3
+ size 1689
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
docker/run/fs/exe/initialize.sh CHANGED
@@ -1,63 +1,3 @@
1
- #!/bin/bash
2
-
3
- echo "Running initialization script..."
4
-
5
- # branch from parameter
6
- if [ -z "$1" ]; then
7
- echo "Error: Branch parameter is empty. Please provide a valid branch name."
8
- exit 1
9
- fi
10
- BRANCH="$1"
11
-
12
- raise_open_file_limit() {
13
- local requested="${A0_NOFILE_LIMIT:-65535}"
14
- local soft
15
- local hard
16
- local target
17
-
18
- if ! [[ "$requested" =~ ^[0-9]+$ ]] || [ "$requested" -lt 1 ]; then
19
- echo "Warning: invalid A0_NOFILE_LIMIT='$requested'; keeping open file limit at $(ulimit -S -n)." >&2
20
- return
21
- fi
22
-
23
- soft="$(ulimit -S -n)"
24
- hard="$(ulimit -H -n)"
25
-
26
- if [ "$soft" = "unlimited" ]; then
27
- echo "Open file limit is already unlimited."
28
- return
29
- fi
30
-
31
- target="$requested"
32
- if [ "$hard" != "unlimited" ] && [ "$target" -gt "$hard" ]; then
33
- target="$hard"
34
- fi
35
-
36
- if [ "$target" -gt "$soft" ]; then
37
- if ulimit -S -n "$target"; then
38
- echo "Raised open file soft limit from $soft to $(ulimit -S -n) (hard: $hard)."
39
- else
40
- echo "Warning: failed to raise open file soft limit from $soft to $target (hard: $hard)." >&2
41
- fi
42
- else
43
- echo "Open file soft limit is $soft (target: $requested, hard: $hard)."
44
- fi
45
- }
46
-
47
- raise_open_file_limit
48
-
49
- # Copy all contents from persistent /per to root directory (/) without overwriting
50
- cp -r --no-preserve=ownership,mode /per/* /
51
-
52
- # Ensure upload storage exists before API and connector callers can reference it.
53
- mkdir -p /a0/usr/uploads
54
-
55
- # allow execution of /root/.bashrc and /root/.profile
56
- chmod 444 /root/.bashrc
57
- chmod 444 /root/.profile
58
-
59
- # update package list to save time later
60
- apt-get update > /dev/null 2>&1 &
61
-
62
- # let supervisord handle the services
63
- exec /usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.conf
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:1fc7c1d54b3d7e6174087f9b63e4b73fc87fd836dc159e544349d73601441d5b
3
+ size 1774
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
docker/run/fs/exe/node_eval.js CHANGED
@@ -1,62 +1,3 @@
1
- #!/usr/bin/env node
2
-
3
- const vm = require('vm');
4
- const path = require('path');
5
- const Module = require('module');
6
-
7
- // Enhance `require` to search CWD first, then globally
8
- function customRequire(moduleName) {
9
- try {
10
- // Try resolving from CWD's node_modules using Node's require.resolve
11
- const cwdPath = require.resolve(moduleName, { paths: [path.join(process.cwd(), 'node_modules')] });
12
- // console.log("resolved path:", cwdPath);
13
- return require(cwdPath);
14
- } catch (cwdErr) {
15
- try {
16
- // Try resolving as a global module
17
- return require(moduleName);
18
- } catch (globalErr) {
19
- console.error(`Cannot find module: ${moduleName}`);
20
- throw globalErr;
21
- }
22
- }
23
- }
24
-
25
- // Create the VM context
26
- const context = vm.createContext({
27
- ...global,
28
- require: customRequire, // Use the custom require
29
- __filename: path.join(process.cwd(), 'eval.js'),
30
- __dirname: process.cwd(),
31
- module: { exports: {} },
32
- exports: module.exports,
33
- console: console,
34
- process: process,
35
- Buffer: Buffer,
36
- setTimeout: setTimeout,
37
- setInterval: setInterval,
38
- setImmediate: setImmediate,
39
- clearTimeout: clearTimeout,
40
- clearInterval: clearInterval,
41
- clearImmediate: clearImmediate,
42
- });
43
-
44
- // Retrieve the code from the command-line argument
45
- const code = process.argv[2];
46
-
47
- const wrappedCode = `
48
- (async function() {
49
- try {
50
- const __result__ = await eval(${JSON.stringify(code)});
51
- if (__result__ !== undefined) console.log('Out[1]:', __result__);
52
- } catch (error) {
53
- console.error(error);
54
- }
55
- })();
56
- `;
57
-
58
- vm.runInContext(wrappedCode, context, {
59
- filename: 'eval.js',
60
- lineOffset: -2,
61
- columnOffset: 0,
62
- }).catch(console.error);
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:b6ddc75ed432d14246ac6c5682634d7467ec632368f163530cbcc46b7b8c3499
3
+ size 1659
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
docker/run/fs/exe/run_A0.sh CHANGED
@@ -1,7 +1,3 @@
1
- #!/bin/bash
2
-
3
- . "/ins/setup_venv.sh" "$@"
4
- . "/ins/copy_A0.sh" "$@"
5
-
6
- echo "Starting A0 bootstrap manager..."
7
- exec python /exe/self_update_manager.py docker-run-ui
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:bbc42594385f5c3187721ce83b2c69886e707bcfd03acee7fc00f0c6763f5ff0
3
+ size 161
 
 
 
 
docker/run/fs/exe/run_searxng.sh CHANGED
@@ -1,10 +1,3 @@
1
- #!/bin/bash
2
-
3
- # start webapp
4
- cd /usr/local/searxng/searxng-src
5
- export SEARXNG_SETTINGS_PATH="/etc/searxng/settings.yml"
6
-
7
- # activate venv
8
- source "/usr/local/searxng/searx-pyenv/bin/activate"
9
-
10
- exec python /usr/local/searxng/searxng-src/searx/webapp.py
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:aa30cf09ba3759f0ec369bb7559347d8478e412cd34f46e1be8ab5bcf4ba561f
3
+ size 249
 
 
 
 
 
 
 
docker/run/fs/exe/run_tunnel_api.sh CHANGED
@@ -1,18 +1,3 @@
1
- #!/bin/bash
2
-
3
- # Wait until run_tunnel.py exists
4
- echo "Starting tunnel API..."
5
-
6
- sleep 1
7
- while [ ! -f /a0/run_tunnel.py ]; do
8
- echo "Waiting for /a0/run_tunnel.py to be available..."
9
- sleep 1
10
- done
11
-
12
- . "/ins/setup_venv.sh" "$@"
13
-
14
- exec python /a0/run_tunnel.py \
15
- --dockerized=true \
16
- --port=80 \
17
- --tunnel_api_port=55520 \
18
- --host="0.0.0.0"
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:1fda7945842d129c82a418731ea0f9f04fc8c196caf19201675375605699a0d3
3
+ size 353
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
docker/run/fs/exe/self_update_manager.py CHANGED
@@ -1,1507 +1,3 @@
1
- #!/usr/bin/env python3
2
- from __future__ import annotations
3
-
4
- import argparse
5
- import importlib.util
6
- import json
7
- import os
8
- import re
9
- import shutil
10
- import signal
11
- import stat
12
- import subprocess
13
- import sys
14
- import tempfile
15
- import time
16
- import urllib.error
17
- import urllib.request
18
- import zipfile
19
- from datetime import UTC, datetime
20
- from pathlib import Path
21
- from typing import Any
22
-
23
- import yaml
24
-
25
-
26
- OFFICIAL_REPO_URL = os.environ.get(
27
- "A0_SELF_UPDATE_REMOTE_URL",
28
- "https://github.com/agent0ai/agent-zero.git",
29
- )
30
- REPO_DIR = Path("/a0")
31
- TRIGGER_FILE = Path("/exe/a0-self-update.yaml")
32
- STATUS_FILE = Path("/exe/a0-self-update-status.yaml")
33
- LOG_FILE = Path("/exe/a0-self-update.log")
34
- DEFAULT_HEALTH_URL = os.environ.get(
35
- "A0_SELF_UPDATE_HEALTH_URL",
36
- "http://127.0.0.1:80/api/health",
37
- )
38
- DEFAULT_HEALTH_TIMEOUT_SECONDS = int(
39
- os.environ.get("A0_SELF_UPDATE_HEALTH_TIMEOUT_SECONDS", "180")
40
- )
41
- DEFAULT_HEALTH_POLL_INTERVAL_SECONDS = float(
42
- os.environ.get("A0_SELF_UPDATE_HEALTH_POLL_INTERVAL_SECONDS", "2")
43
- )
44
- DEFAULT_BACKUP_DIR = "/root/update-backups"
45
- DEFAULT_BACKUP_CONFLICT_POLICY = "rename"
46
- BACKUP_CONFLICT_POLICIES = {"rename", "overwrite", "fail"}
47
- MIN_SELECTOR_VERSION = (1, 0)
48
- LATEST_SELECTOR_TAG = "latest"
49
- DESKTOP_PROFILE_STATE_RELATIVE_DIRS = (
50
- Path("usr/plugins/_desktop/profiles"),
51
- Path("usr/_desktop/profiles"),
52
- Path("tmp/_office/desktop/profiles"),
53
- )
54
-
55
-
56
- def now_iso() -> str:
57
- return datetime.now(UTC).isoformat().replace("+00:00", "Z")
58
-
59
-
60
- class AttemptLogger:
61
- def __init__(self, path: Path):
62
- self.path = path
63
-
64
- def reset(self) -> None:
65
- self.path.parent.mkdir(parents=True, exist_ok=True)
66
- self.path.write_text("", encoding="utf-8")
67
-
68
- def log(self, message: str = "") -> None:
69
- line = f"[{now_iso()}] {message}".rstrip()
70
- print(f"[a0-self-update] {message}", flush=True)
71
- with self.path.open("a", encoding="utf-8") as handle:
72
- handle.write(line + "\n")
73
-
74
- def log_block(self, title: str, content: str) -> None:
75
- cleaned = content.rstrip()
76
- self.log(f"{title}:")
77
- if not cleaned:
78
- self.log("(empty)")
79
- return
80
- with self.path.open("a", encoding="utf-8") as handle:
81
- for line in cleaned.splitlines():
82
- handle.write(f" {line}\n")
83
-
84
-
85
- class NullLogger:
86
- def reset(self) -> None:
87
- return
88
-
89
- def log(self, message: str = "") -> None:
90
- return
91
-
92
- def log_block(self, title: str, content: str) -> None:
93
- return
94
-
95
-
96
- def load_yaml(path: Path) -> dict[str, Any] | None:
97
- if not path.exists():
98
- return None
99
- loaded = yaml.safe_load(path.read_text(encoding="utf-8"))
100
- return loaded if isinstance(loaded, dict) else None
101
-
102
-
103
- def write_yaml(path: Path, payload: dict[str, Any]) -> None:
104
- path.parent.mkdir(parents=True, exist_ok=True)
105
- path.write_text(
106
- yaml.safe_dump(payload, allow_unicode=True, sort_keys=False),
107
- encoding="utf-8",
108
- )
109
-
110
-
111
- def write_status(payload: dict[str, Any]) -> None:
112
- write_yaml(STATUS_FILE, payload)
113
-
114
-
115
- def git_output(repo_dir: Path, *args: str) -> str:
116
- completed = subprocess.run(
117
- ["git", "-C", str(repo_dir), *args],
118
- check=True,
119
- text=True,
120
- capture_output=True,
121
- env={**os.environ, "GIT_TERMINAL_PROMPT": "0"},
122
- )
123
- return completed.stdout.strip()
124
-
125
-
126
- def normalize_describe_to_version(describe: str) -> str:
127
- match = re.fullmatch(r"(.+)-\d+-g[0-9a-f]+", describe)
128
- if match:
129
- return match.group(1)
130
- return describe
131
-
132
-
133
- def split_describe_version(describe: str) -> tuple[str, int]:
134
- normalized = describe.strip()
135
- match = re.fullmatch(r"(.+)-(\d+)-g[0-9a-f]+", normalized)
136
- if not match:
137
- return normalized, 0
138
- return match.group(1), int(match.group(2))
139
-
140
-
141
- def parse_selector_version(tag: str) -> tuple[int, int] | None:
142
- match = re.fullmatch(r"v(\d+)\.(\d+)", tag.strip())
143
- if not match:
144
- return None
145
- return int(match.group(1)), int(match.group(2))
146
-
147
-
148
- def is_valid_selector_tag(tag: str) -> bool:
149
- return parse_selector_version(tag) is not None
150
-
151
-
152
- def is_supported_selector_tag(tag: str) -> bool:
153
- parsed = parse_selector_version(tag)
154
- return parsed is not None and parsed >= MIN_SELECTOR_VERSION
155
-
156
-
157
- def sort_selector_supported_tags(tags: list[str]) -> list[str]:
158
- return sorted(
159
- tags,
160
- key=lambda tag: parse_selector_version(tag) or (-1, -1),
161
- reverse=True,
162
- )
163
-
164
-
165
- def parse_major_version(tag: str) -> int | None:
166
- match = re.fullmatch(r"v(\d+)(?:[.-].*)?", tag.strip())
167
- if not match:
168
- return None
169
- return int(match.group(1))
170
-
171
-
172
- def is_latest_selector_tag(tag: str) -> bool:
173
- return tag.strip().lower() == LATEST_SELECTOR_TAG
174
-
175
-
176
- def get_tag_commit_ref(tag: str) -> str:
177
- return f"refs/tags/{tag}^{{commit}}"
178
-
179
-
180
- def build_default_backup_name() -> str:
181
- timestamp = datetime.now(UTC).strftime("%Y%m%d-%H%M%S")
182
- return f"usr-{timestamp}.zip"
183
-
184
-
185
- def normalize_requested_tag(tag: str) -> str:
186
- normalized = (tag or "").strip()
187
- if not normalized:
188
- return LATEST_SELECTOR_TAG
189
- if is_latest_selector_tag(normalized):
190
- return LATEST_SELECTOR_TAG
191
- if not is_valid_selector_tag(normalized):
192
- raise ValueError("Release tag must use the format vX.Y.")
193
- if not is_supported_selector_tag(normalized):
194
- raise ValueError("Release tag must be v1.0 or newer.")
195
- return normalized
196
-
197
-
198
- def normalize_backup_conflict_policy(conflict_policy: str) -> str:
199
- normalized = (conflict_policy or DEFAULT_BACKUP_CONFLICT_POLICY).strip().lower()
200
- if normalized not in BACKUP_CONFLICT_POLICIES:
201
- raise ValueError("Backup conflict policy must be one of: rename, overwrite, fail.")
202
- return normalized
203
-
204
-
205
- def get_latest_same_major_tag(
206
- repo_dir: Path,
207
- *,
208
- branch_ref: str,
209
- current_version: str,
210
- ) -> str:
211
- current_major = parse_major_version(current_version)
212
- if current_major is None:
213
- raise RuntimeError(
214
- f"Could not determine the installed major version from {current_version}. "
215
- "Use an explicit tag instead of latest."
216
- )
217
-
218
- output = git_output(repo_dir, "tag", "--merged", branch_ref)
219
- same_major_tags = [
220
- tag
221
- for tag in (line.strip() for line in output.splitlines())
222
- if is_supported_selector_tag(tag) and parse_major_version(tag) == current_major
223
- ]
224
- if not same_major_tags:
225
- raise RuntimeError(
226
- f"No v{current_major}.x release tags are reachable from branch "
227
- f"{branch_ref.rsplit('/', 1)[-1]}."
228
- )
229
- return sort_selector_supported_tags(same_major_tags)[0]
230
-
231
-
232
- def ensure_latest_target_matches_current_major(
233
- *,
234
- branch: str,
235
- current_version: str,
236
- target_version: str,
237
- ) -> None:
238
- current_major = parse_major_version(current_version)
239
- if current_major is None:
240
- raise RuntimeError(
241
- f"Could not determine the installed major version from {current_version}. "
242
- "Use an explicit tag instead of latest."
243
- )
244
-
245
- target_major = parse_major_version(target_version)
246
- if target_major is None or not is_supported_selector_tag(target_version):
247
- raise RuntimeError(
248
- f"Could not resolve latest on branch {branch} to a supported vX.Y release. "
249
- "Use an explicit tag instead."
250
- )
251
-
252
- if target_major != current_major:
253
- raise RuntimeError(
254
- f"Latest on branch {branch} resolves to {target_version}, but the installed "
255
- f"version is {current_version}. Use an explicit tag to change major versions."
256
- )
257
-
258
-
259
- def get_repo_version_info(repo_dir: Path) -> dict[str, str]:
260
- describe = git_output(repo_dir, "describe", "--tags", "--always")
261
- commit = git_output(repo_dir, "rev-parse", "HEAD")
262
- branch = git_optional_output(repo_dir, "branch", "--show-current")
263
- return {
264
- "branch": branch,
265
- "describe": describe,
266
- "short_tag": normalize_describe_to_version(describe),
267
- "commit": commit,
268
- "short_commit": commit[:7],
269
- }
270
-
271
-
272
- def git_optional_output(repo_dir: Path, *args: str) -> str:
273
- completed = subprocess.run(
274
- ["git", "-C", str(repo_dir), *args],
275
- check=False,
276
- text=True,
277
- capture_output=True,
278
- env={**os.environ, "GIT_TERMINAL_PROMPT": "0"},
279
- )
280
- if completed.returncode != 0:
281
- return ""
282
- return completed.stdout.strip()
283
-
284
-
285
- def remove_path(path: Path) -> None:
286
- if path.is_symlink() or path.is_file():
287
- path.unlink(missing_ok=True)
288
- return
289
- if path.exists():
290
- shutil.rmtree(path)
291
-
292
-
293
- def get_repo_relative_path(repo_dir: Path, path: Path) -> str | None:
294
- try:
295
- return path.resolve().relative_to(repo_dir.resolve()).as_posix()
296
- except ValueError:
297
- return None
298
-
299
-
300
- def sanitize_filename(name: str, default_name: str) -> str:
301
- raw = (name or "").strip()
302
- if not raw:
303
- raw = default_name
304
- raw = Path(raw).name
305
- raw = re.sub(r"[^A-Za-z0-9._-]+", "-", raw).strip(".-") or default_name
306
- if not raw.lower().endswith(".zip"):
307
- raw = f"{raw}.zip"
308
- return raw
309
-
310
-
311
- def resolve_backup_destination(
312
- directory: Path,
313
- filename: str,
314
- conflict_policy: str,
315
- ) -> Path:
316
- normalized_policy = conflict_policy.strip().lower()
317
- directory.mkdir(parents=True, exist_ok=True)
318
- destination = directory / filename
319
- if not destination.exists():
320
- return destination
321
-
322
- if normalized_policy == "overwrite":
323
- remove_path(destination)
324
- return destination
325
- if normalized_policy == "fail":
326
- raise FileExistsError(f"Backup file already exists: {destination}")
327
- if normalized_policy != "rename":
328
- raise ValueError("backup_conflict_policy must be rename, overwrite, or fail.")
329
-
330
- stem = destination.stem
331
- suffix = destination.suffix
332
- index = 2
333
- while True:
334
- candidate = directory / f"{stem}-{index}{suffix}"
335
- if not candidate.exists():
336
- return candidate
337
- index += 1
338
-
339
-
340
- def create_usr_backup(
341
- *,
342
- repo_dir: Path,
343
- backup_path: str,
344
- backup_name: str,
345
- conflict_policy: str,
346
- logger: AttemptLogger,
347
- ) -> Path:
348
- usr_dir = repo_dir / "usr"
349
- if not usr_dir.exists():
350
- raise FileNotFoundError(f"User directory not found: {usr_dir}")
351
-
352
- destination_dir = Path(backup_path)
353
- if not destination_dir.is_absolute():
354
- destination_dir = (repo_dir / destination_dir).resolve()
355
- else:
356
- destination_dir = destination_dir.resolve()
357
- destination_name = sanitize_filename(backup_name, "agent-zero-usr-backup.zip")
358
- destination = resolve_backup_destination(destination_dir, destination_name, conflict_policy)
359
-
360
- temp_fd, temp_path = tempfile.mkstemp(suffix=".zip")
361
- os.close(temp_fd)
362
- temporary_backup = Path(temp_path)
363
-
364
- try:
365
- with zipfile.ZipFile(
366
- temporary_backup,
367
- "w",
368
- compression=zipfile.ZIP_DEFLATED,
369
- compresslevel=6,
370
- ) as archive:
371
- for root, dirs, files in os.walk(usr_dir):
372
- root_path = Path(root)
373
- root_relative = root_path.relative_to(usr_dir)
374
- dirs[:] = [
375
- dirname
376
- for dirname in dirs
377
- if not should_exclude_from_usr_backup(
378
- root_relative / dirname,
379
- logger,
380
- )
381
- ]
382
- for filename in files:
383
- source_file = root_path / filename
384
- if not should_include_usr_backup_entry(source_file, logger):
385
- continue
386
- archive_name = Path("usr") / source_file.relative_to(usr_dir)
387
- try:
388
- archive.write(source_file, archive_name.as_posix())
389
- except FileNotFoundError:
390
- logger.log(f"Skipping vanished usr backup entry: {source_file}")
391
- except OSError as exc:
392
- logger.log(f"Skipping usr backup entry after read error: {source_file}: {exc}")
393
-
394
- destination.parent.mkdir(parents=True, exist_ok=True)
395
- shutil.move(str(temporary_backup), str(destination))
396
- logger.log(f"Created usr backup at {destination}")
397
- return destination
398
- finally:
399
- if temporary_backup.exists():
400
- temporary_backup.unlink(missing_ok=True)
401
-
402
-
403
- def should_exclude_from_usr_backup(
404
- relative_dir: Path,
405
- logger: AttemptLogger,
406
- ) -> bool:
407
- parts = relative_dir.parts
408
- if parts and parts[0] == ".time_travel":
409
- logger.log(
410
- f"Skipping Time Travel history during usr backup: {Path('usr') / relative_dir}"
411
- )
412
- return True
413
- if (
414
- len(parts) >= 6
415
- and parts[0] == "plugins"
416
- and parts[1] == "_desktop"
417
- and parts[2] == "profiles"
418
- and parts[-2] == ".ssh"
419
- and parts[-1] == "agent"
420
- ):
421
- logger.log(f"Skipping transient usr backup directory: {Path('usr') / relative_dir}")
422
- return True
423
- return False
424
-
425
-
426
- def should_include_usr_backup_entry(source_file: Path, logger: AttemptLogger) -> bool:
427
- try:
428
- source_stat = source_file.lstat()
429
- except FileNotFoundError:
430
- logger.log(f"Skipping vanished usr backup entry: {source_file}")
431
- return False
432
- except OSError as exc:
433
- logger.log(f"Skipping unreadable usr backup entry: {source_file}: {exc}")
434
- return False
435
-
436
- if stat.S_ISLNK(source_stat.st_mode):
437
- try:
438
- target_stat = source_file.stat()
439
- except FileNotFoundError:
440
- logger.log(f"Skipping broken symlink during usr backup: {source_file}")
441
- return False
442
- except OSError as exc:
443
- logger.log(
444
- f"Skipping unreadable symlink target during usr backup: {source_file}: {exc}"
445
- )
446
- return False
447
- if not stat.S_ISREG(target_stat.st_mode):
448
- logger.log(
449
- f"Skipping non-regular symlink target during usr backup: {source_file}"
450
- )
451
- return False
452
- return True
453
-
454
- if not stat.S_ISREG(source_stat.st_mode):
455
- logger.log(f"Skipping non-regular usr backup entry: {source_file}")
456
- return False
457
-
458
- return True
459
-
460
-
461
- def clean_transient_desktop_agent_state(
462
- repo_dir: Path,
463
- logger: AttemptLogger,
464
- ) -> None:
465
- profile_roots = 0
466
- removed = 0
467
- for relative_root in DESKTOP_PROFILE_STATE_RELATIVE_DIRS:
468
- profile_root = repo_dir / relative_root
469
- if not _is_cleanup_directory(
470
- profile_root,
471
- logger,
472
- "Desktop profile state",
473
- missing_ok=True,
474
- ):
475
- continue
476
- profile_roots += 1
477
- try:
478
- profiles = list(profile_root.iterdir())
479
- except OSError as exc:
480
- logger.log(f"Desktop profile state could not be listed: {profile_root}: {exc}")
481
- continue
482
- for profile_dir in profiles:
483
- if not _is_cleanup_directory(profile_dir, logger, "Desktop profile"):
484
- continue
485
- removed += _clean_directory_entries(
486
- profile_dir / ".ssh" / "agent",
487
- logger,
488
- label="desktop SSH agent",
489
- )
490
- removed += _clean_gnupg_agent_entries(profile_dir / ".gnupg", logger)
491
-
492
- if removed:
493
- logger.log(f"Removed {removed} transient desktop agent entries.")
494
- elif profile_roots:
495
- logger.log("Transient desktop agent state already clean.")
496
- else:
497
- logger.log("No desktop profile runtime state found, skipping transient agent cleanup.")
498
-
499
-
500
- def _clean_gnupg_agent_entries(gnupg_dir: Path, logger: AttemptLogger) -> int:
501
- if not _is_cleanup_directory(gnupg_dir, logger, "desktop GnuPG state", missing_ok=True):
502
- return 0
503
- try:
504
- entries = list(gnupg_dir.iterdir())
505
- except OSError as exc:
506
- logger.log(f"Desktop GnuPG state could not be listed: {gnupg_dir}: {exc}")
507
- return 0
508
-
509
- removed = 0
510
- for entry in entries:
511
- if not entry.name.startswith("S.gpg-agent"):
512
- continue
513
- try:
514
- entry_stat = entry.lstat()
515
- except FileNotFoundError:
516
- continue
517
- except OSError as exc:
518
- logger.log(f"Skipping transient desktop GnuPG agent entry after stat error: {entry}: {exc}")
519
- continue
520
- if stat.S_ISREG(entry_stat.st_mode):
521
- continue
522
- if _remove_cleanup_entry(entry, entry_stat, logger, label="desktop GnuPG agent"):
523
- removed += 1
524
- return removed
525
-
526
-
527
- def _clean_directory_entries(directory: Path, logger: AttemptLogger, *, label: str) -> int:
528
- if not _is_cleanup_directory(directory, logger, label, missing_ok=True):
529
- return 0
530
- try:
531
- entries = list(directory.iterdir())
532
- except OSError as exc:
533
- logger.log(f"Transient {label} directory could not be listed: {directory}: {exc}")
534
- return 0
535
-
536
- removed = 0
537
- for entry in entries:
538
- try:
539
- entry_stat = entry.lstat()
540
- except FileNotFoundError:
541
- continue
542
- except OSError as exc:
543
- logger.log(f"Skipping transient {label} entry after stat error: {entry}: {exc}")
544
- continue
545
- if _remove_cleanup_entry(entry, entry_stat, logger, label=label):
546
- removed += 1
547
- return removed
548
-
549
-
550
- def _is_cleanup_directory(
551
- directory: Path,
552
- logger: AttemptLogger,
553
- label: str,
554
- *,
555
- missing_ok: bool = False,
556
- ) -> bool:
557
- try:
558
- directory_stat = directory.lstat()
559
- except FileNotFoundError:
560
- if not missing_ok:
561
- logger.log(f"{label} directory not found, skipping: {directory}")
562
- return False
563
- except OSError as exc:
564
- logger.log(f"{label} directory could not be inspected: {directory}: {exc}")
565
- return False
566
-
567
- if stat.S_ISLNK(directory_stat.st_mode) or not stat.S_ISDIR(directory_stat.st_mode):
568
- logger.log(f"{label} path is not a directory, skipping: {directory}")
569
- return False
570
- return True
571
-
572
-
573
- def _remove_cleanup_entry(
574
- entry: Path,
575
- entry_stat: os.stat_result,
576
- logger: AttemptLogger,
577
- *,
578
- label: str,
579
- ) -> bool:
580
- try:
581
- if stat.S_ISDIR(entry_stat.st_mode):
582
- shutil.rmtree(entry)
583
- else:
584
- entry.unlink(missing_ok=True)
585
- return True
586
- except FileNotFoundError:
587
- return False
588
- except OSError as exc:
589
- logger.log(f"Skipping transient {label} entry after error: {entry}: {exc}")
590
- return False
591
-
592
-
593
- def run_command(
594
- command: list[str],
595
- *,
596
- cwd: Path | None,
597
- logger: AttemptLogger,
598
- error_message: str | None = None,
599
- ) -> subprocess.CompletedProcess[str]:
600
- logger.log(f"$ {' '.join(command)}")
601
- completed = subprocess.run(
602
- command,
603
- cwd=cwd,
604
- text=True,
605
- capture_output=True,
606
- env={**os.environ, "GIT_TERMINAL_PROMPT": "0"},
607
- )
608
- if completed.stdout:
609
- logger.log_block("stdout", completed.stdout)
610
- if completed.stderr:
611
- logger.log_block("stderr", completed.stderr)
612
- if completed.returncode != 0:
613
- raise RuntimeError(
614
- error_message
615
- or f"Command failed with exit code {completed.returncode}: {' '.join(command)}"
616
- )
617
- return completed
618
-
619
-
620
- def clean_uv_cache(logger: AttemptLogger) -> None:
621
- uv_path = shutil.which("uv")
622
- if not uv_path:
623
- logger.log("uv executable not found, skipping uv cache clean.")
624
- return
625
-
626
- logger.log("Cleaning uv cache before continuing self-update startup.")
627
- try:
628
- run_command(
629
- [uv_path, "cache", "clean"],
630
- cwd=None,
631
- logger=logger,
632
- error_message="Failed to clean uv cache during self-update.",
633
- )
634
- except Exception as exc:
635
- logger.log(f"uv cache clean skipped after error: {exc}")
636
-
637
-
638
- def refresh_codex_cli(logger: AttemptLogger) -> None:
639
- codex_path = shutil.which("codex")
640
- if not codex_path:
641
- logger.log("Codex CLI not installed, skipping Codex refresh.")
642
- return
643
-
644
- npm_path = shutil.which("npm")
645
- if not npm_path:
646
- logger.log("npm executable not found, skipping Codex refresh.")
647
- return
648
-
649
- logger.log("Refreshing the installed Codex CLI after self-update.")
650
- try:
651
- run_command(
652
- [npm_path, "install", "--global", "@openai/codex@latest"],
653
- cwd=None,
654
- logger=logger,
655
- error_message="Failed to refresh the installed Codex CLI.",
656
- )
657
- except Exception as exc:
658
- logger.log(f"Codex CLI refresh skipped after error: {exc}")
659
-
660
-
661
- def has_local_rollback_changes(repo_dir: Path) -> bool:
662
- status = git_output(repo_dir, "status", "--porcelain=v1", "--untracked-files=all")
663
- return bool(status.strip())
664
-
665
-
666
- def get_top_stash_ref(repo_dir: Path) -> str:
667
- return git_optional_output(repo_dir, "stash", "list", "--format=%gd", "-n", "1")
668
-
669
-
670
- def create_rollback_stash(repo_dir: Path, logger: AttemptLogger) -> str | None:
671
- if not has_local_rollback_changes(repo_dir):
672
- logger.log("No tracked or non-ignored untracked changes need rollback protection.")
673
- return None
674
-
675
- previous_top = get_top_stash_ref(repo_dir)
676
- message = f"a0-self-update rollback snapshot {now_iso()}"
677
- run_command(
678
- [
679
- "git",
680
- "-C",
681
- str(repo_dir),
682
- "stash",
683
- "push",
684
- "--include-untracked",
685
- "--message",
686
- message,
687
- ],
688
- cwd=None,
689
- logger=logger,
690
- error_message="Failed to save local tracked/untracked changes before updating.",
691
- )
692
- stash_ref = get_top_stash_ref(repo_dir)
693
- if not stash_ref or stash_ref == previous_top:
694
- raise RuntimeError("Failed to create the pre-update rollback stash.")
695
- logger.log(
696
- f"Saved local tracked/untracked changes into {stash_ref}. "
697
- "Ignored files stay in place and are not stashed."
698
- )
699
- return stash_ref
700
-
701
-
702
- def drop_stash(repo_dir: Path, stash_ref: str, logger: AttemptLogger) -> None:
703
- if not stash_ref:
704
- return
705
- run_command(
706
- ["git", "-C", str(repo_dir), "stash", "drop", stash_ref],
707
- cwd=None,
708
- logger=logger,
709
- error_message=f"Failed to drop temporary rollback stash {stash_ref}.",
710
- )
711
-
712
-
713
- def apply_stash(repo_dir: Path, stash_ref: str, logger: AttemptLogger) -> None:
714
- if not stash_ref:
715
- return
716
- run_command(
717
- ["git", "-C", str(repo_dir), "stash", "apply", "--index", stash_ref],
718
- cwd=None,
719
- logger=logger,
720
- error_message=(
721
- f"Failed to restore local tracked/untracked changes from {stash_ref}. "
722
- "The stash entry has been kept so it can be recovered manually."
723
- ),
724
- )
725
- try:
726
- drop_stash(repo_dir, stash_ref, logger)
727
- except Exception as exc:
728
- logger.log(
729
- f"Rollback stash {stash_ref} was restored but could not be dropped automatically: {exc}"
730
- )
731
-
732
-
733
- def clean_repo_worktree(
734
- repo_dir: Path,
735
- logger: AttemptLogger,
736
- *,
737
- exclude_paths: list[Path] | None = None,
738
- ) -> None:
739
- command = ["git", "-C", str(repo_dir), "clean", "-ffd"]
740
- for path in exclude_paths or []:
741
- relative_path = get_repo_relative_path(repo_dir, path)
742
- if relative_path:
743
- command.extend(["-e", relative_path])
744
- run_command(
745
- command,
746
- cwd=None,
747
- logger=logger,
748
- error_message="Failed to remove leftover non-ignored files after checkout.",
749
- )
750
-
751
-
752
- def fetch_release_refs(repo_dir: Path, branch: str, tag: str, logger: AttemptLogger) -> None:
753
- remote_branch_ref = f"refs/remotes/a0-self-update/{branch}"
754
- tag_commit_ref = get_tag_commit_ref(tag)
755
- logger.log(f"Fetching branch {branch} and tag {tag} from {OFFICIAL_REPO_URL}")
756
- run_command(
757
- [
758
- "git",
759
- "-C",
760
- str(repo_dir),
761
- "fetch",
762
- "--force",
763
- OFFICIAL_REPO_URL,
764
- f"+refs/heads/{branch}:{remote_branch_ref}",
765
- f"+refs/tags/{tag}:refs/tags/{tag}",
766
- ],
767
- cwd=None,
768
- logger=logger,
769
- error_message=f"Failed to fetch branch {branch} and tag {tag} from the official repository.",
770
- )
771
- run_command(
772
- [
773
- "git",
774
- "-C",
775
- str(repo_dir),
776
- "merge-base",
777
- "--is-ancestor",
778
- tag_commit_ref,
779
- remote_branch_ref,
780
- ],
781
- cwd=None,
782
- logger=logger,
783
- error_message=f"Requested tag {tag} is not reachable from official branch {branch}.",
784
- )
785
-
786
-
787
- def fetch_branch_refs(repo_dir: Path, branch: str, logger: AttemptLogger) -> str:
788
- remote_branch_ref = f"refs/remotes/a0-self-update/{branch}"
789
- logger.log(f"Fetching branch {branch} and tags from {OFFICIAL_REPO_URL}")
790
- run_command(
791
- [
792
- "git",
793
- "-C",
794
- str(repo_dir),
795
- "fetch",
796
- "--force",
797
- "--tags",
798
- OFFICIAL_REPO_URL,
799
- f"+refs/heads/{branch}:{remote_branch_ref}",
800
- ],
801
- cwd=None,
802
- logger=logger,
803
- error_message=f"Failed to fetch branch {branch} from the official repository.",
804
- )
805
- return remote_branch_ref
806
-
807
-
808
- def resolve_requested_target(
809
- repo_dir: Path,
810
- branch: str,
811
- tag: str,
812
- current_version: str,
813
- logger: AttemptLogger,
814
- ) -> dict[str, str]:
815
- normalized_tag = tag.strip()
816
-
817
- if not is_latest_selector_tag(normalized_tag):
818
- fetch_release_refs(repo_dir, branch, normalized_tag, logger)
819
- tag_commit_ref = get_tag_commit_ref(normalized_tag)
820
- return {
821
- "requested_tag": normalized_tag,
822
- "effective_tag": normalized_tag,
823
- "target_ref": f"refs/tags/{normalized_tag}",
824
- "expected_short_tag": normalized_tag,
825
- "expected_commit": git_output(repo_dir, "rev-parse", tag_commit_ref),
826
- "target_description": f"tag {normalized_tag}",
827
- }
828
-
829
- remote_branch_ref = fetch_branch_refs(repo_dir, branch, logger)
830
- if branch == "main":
831
- effective_tag = get_latest_same_major_tag(
832
- repo_dir,
833
- branch_ref=remote_branch_ref,
834
- current_version=current_version,
835
- )
836
- tag_commit_ref = get_tag_commit_ref(effective_tag)
837
- logger.log(f"Resolved latest on main to tag {effective_tag}")
838
- return {
839
- "requested_tag": LATEST_SELECTOR_TAG,
840
- "effective_tag": effective_tag,
841
- "target_ref": f"refs/tags/{effective_tag}",
842
- "expected_short_tag": effective_tag,
843
- "expected_commit": git_output(repo_dir, "rev-parse", tag_commit_ref),
844
- "target_description": f"latest tag {effective_tag}",
845
- }
846
-
847
- head_describe = git_output(repo_dir, "describe", "--tags", "--always", remote_branch_ref)
848
- head_short_tag = normalize_describe_to_version(head_describe)
849
- head_commit = git_output(repo_dir, "rev-parse", remote_branch_ref)
850
- ensure_latest_target_matches_current_major(
851
- branch=branch,
852
- current_version=current_version,
853
- target_version=head_short_tag,
854
- )
855
- logger.log(
856
- f"Resolved latest on branch {branch} to commit {head_commit[:7]} ({head_describe})"
857
- )
858
- return {
859
- "requested_tag": LATEST_SELECTOR_TAG,
860
- "effective_tag": head_short_tag,
861
- "target_ref": remote_branch_ref,
862
- "expected_short_tag": head_short_tag,
863
- "expected_commit": head_commit,
864
- "target_description": f"latest branch state {head_describe}",
865
- }
866
-
867
-
868
- def checkout_target_release(
869
- repo_dir: Path,
870
- branch: str,
871
- target_ref: str,
872
- target_description: str,
873
- logger: AttemptLogger,
874
- *,
875
- exclude_paths: list[Path] | None = None,
876
- ) -> None:
877
- logger.log(f"Checking out branch {branch} at {target_description}")
878
- run_command(
879
- [
880
- "git",
881
- "-C",
882
- str(repo_dir),
883
- "checkout",
884
- "-B",
885
- branch,
886
- target_ref,
887
- ],
888
- cwd=None,
889
- logger=logger,
890
- error_message=f"Failed to check out requested {target_description} on branch {branch}.",
891
- )
892
- clean_repo_worktree(repo_dir, logger, exclude_paths=exclude_paths)
893
-
894
-
895
- def restore_git_state(
896
- repo_dir: Path,
897
- *,
898
- head: str,
899
- branch: str,
900
- logger: AttemptLogger,
901
- exclude_paths: list[Path] | None = None,
902
- ) -> None:
903
- logger.log(f"Restoring repository state to commit {head}")
904
- if branch:
905
- run_command(
906
- [
907
- "git",
908
- "-C",
909
- str(repo_dir),
910
- "checkout",
911
- "-B",
912
- branch,
913
- head,
914
- ],
915
- cwd=None,
916
- logger=logger,
917
- error_message=f"Failed to restore branch {branch} to commit {head}.",
918
- )
919
- else:
920
- run_command(
921
- [
922
- "git",
923
- "-C",
924
- str(repo_dir),
925
- "checkout",
926
- "--detach",
927
- head,
928
- ],
929
- cwd=None,
930
- logger=logger,
931
- error_message=f"Failed to restore detached HEAD at commit {head}.",
932
- )
933
- clean_repo_worktree(repo_dir, logger, exclude_paths=exclude_paths)
934
-
935
-
936
- def launch_ui_process(repo_dir: Path, logger: AttemptLogger) -> subprocess.Popen[bytes]:
937
- run_office_cleanup_hook(repo_dir, logger)
938
-
939
- prepare_script = repo_dir / "prepare.py"
940
- if prepare_script.exists():
941
- logger.log("Running prepare.py before UI start")
942
- run_command([sys.executable, str(prepare_script), "--dockerized=true"], cwd=repo_dir, logger=logger)
943
- else:
944
- logger.log("prepare.py not found, skipping prepare step")
945
-
946
- logger.log("Starting Agent Zero UI")
947
- return subprocess.Popen(
948
- [
949
- sys.executable,
950
- str(repo_dir / "run_ui.py"),
951
- "--dockerized=true",
952
- "--port=80",
953
- "--host=0.0.0.0",
954
- ],
955
- cwd=repo_dir,
956
- )
957
-
958
-
959
- def run_office_cleanup_hook(repo_dir: Path, logger: AttemptLogger) -> None:
960
- hook_path = repo_dir / "plugins" / "_office" / "hooks.py"
961
- if not hook_path.exists():
962
- return
963
- try:
964
- if str(repo_dir) not in sys.path:
965
- sys.path.insert(0, str(repo_dir))
966
- spec = importlib.util.spec_from_file_location("a0_office_hooks", hook_path)
967
- if spec is None or spec.loader is None:
968
- logger.log("Office cleanup hook could not be loaded.")
969
- return
970
- module = importlib.util.module_from_spec(spec)
971
- spec.loader.exec_module(module)
972
- cleanup = getattr(module, "cleanup_stale_runtime_state", None)
973
- if not callable(cleanup):
974
- return
975
- result = cleanup()
976
- if isinstance(result, dict) and result.get("errors"):
977
- logger.log(f"Office cleanup hook reported errors: {result.get('errors')}")
978
- else:
979
- logger.log("Office cleanup hook completed.")
980
- except Exception as exc:
981
- logger.log(f"Office cleanup hook skipped after error: {exc}")
982
-
983
-
984
- def wait_for_health(
985
- process: subprocess.Popen[bytes],
986
- *,
987
- health_url: str,
988
- timeout_seconds: int,
989
- poll_interval_seconds: float,
990
- expected_version: str | None = None,
991
- expected_commit: str | None = None,
992
- logger: AttemptLogger,
993
- ) -> tuple[bool, dict[str, Any] | str]:
994
- deadline = time.monotonic() + timeout_seconds
995
- last_error = "Health check did not return a successful response."
996
-
997
- while time.monotonic() < deadline:
998
- if process.poll() is not None:
999
- return (
1000
- False,
1001
- f"UI process exited with code {process.returncode} before passing the health check.",
1002
- )
1003
- try:
1004
- request = urllib.request.Request(
1005
- health_url,
1006
- headers={"Cache-Control": "no-cache"},
1007
- method="GET",
1008
- )
1009
- with urllib.request.urlopen(request, timeout=5) as response:
1010
- body = response.read().decode("utf-8")
1011
- payload = json.loads(body) if body else {}
1012
- git_info = payload.get("gitinfo") or {}
1013
- current_version = (git_info.get("short_tag") or "").strip()
1014
- current_commit = (git_info.get("commit_hash") or "").strip()
1015
- if expected_commit and current_commit and current_commit != expected_commit:
1016
- last_error = (
1017
- f"Health check responded, but commit {current_commit} does not match "
1018
- f"expected {expected_commit}."
1019
- )
1020
- elif expected_version and current_version and current_version != expected_version:
1021
- last_error = (
1022
- f"Health check responded, but version {current_version} does not match "
1023
- f"expected {expected_version}."
1024
- )
1025
- elif response.status == 200:
1026
- logger.log(f"Health check passed at {health_url}")
1027
- return True, payload
1028
- except (urllib.error.URLError, TimeoutError, ValueError, json.JSONDecodeError) as exc:
1029
- last_error = str(exc)
1030
-
1031
- time.sleep(poll_interval_seconds)
1032
-
1033
- return False, last_error
1034
-
1035
-
1036
- def terminate_process(process: subprocess.Popen[bytes], timeout_seconds: int = 20) -> None:
1037
- if process.poll() is not None:
1038
- return
1039
- process.terminate()
1040
- try:
1041
- process.wait(timeout=timeout_seconds)
1042
- except subprocess.TimeoutExpired:
1043
- process.kill()
1044
- process.wait(timeout=5)
1045
-
1046
-
1047
- def wait_for_process(process: subprocess.Popen[bytes]) -> int:
1048
- def forward_signal(signum, _frame) -> None:
1049
- if process.poll() is None:
1050
- process.send_signal(signum)
1051
-
1052
- for sig in (signal.SIGTERM, signal.SIGINT):
1053
- try:
1054
- signal.signal(sig, forward_signal)
1055
- except ValueError:
1056
- pass
1057
-
1058
- return process.wait()
1059
-
1060
-
1061
- def record_result(
1062
- *,
1063
- status: str,
1064
- message: str,
1065
- request_data: dict[str, Any],
1066
- source_info: dict[str, str],
1067
- current_version: str,
1068
- started_at: str,
1069
- backup_zip_path: str = "",
1070
- rollback_applied: bool = False,
1071
- error: str = "",
1072
- ) -> None:
1073
- payload: dict[str, Any] = {
1074
- "status": status,
1075
- "message": message,
1076
- "branch": str(request_data.get("branch", "")),
1077
- "tag": str(request_data.get("tag", "")),
1078
- "source_version": source_info["short_tag"],
1079
- "source_commit": source_info["commit"],
1080
- "current_version": current_version,
1081
- "requested_at": str(request_data.get("requested_at", "")),
1082
- "started_at": started_at,
1083
- "finished_at": now_iso(),
1084
- "log_file_path": str(LOG_FILE),
1085
- "update_file_path": str(TRIGGER_FILE),
1086
- "rollback_applied": rollback_applied,
1087
- }
1088
- if backup_zip_path:
1089
- payload["backup_zip_path"] = backup_zip_path
1090
- if error:
1091
- payload["error"] = error
1092
- write_status(payload)
1093
-
1094
-
1095
- def execute_pending_update(
1096
- request_data: dict[str, Any],
1097
- *,
1098
- logger: AttemptLogger,
1099
- ) -> subprocess.Popen[bytes]:
1100
- source_info = get_repo_version_info(REPO_DIR)
1101
- started_at = now_iso()
1102
- backup_zip_path = ""
1103
- stash_ref: str | None = None
1104
- repository_changed = False
1105
- branch = str(request_data.get("branch", "")).strip()
1106
- tag = str(request_data.get("tag", "")).strip()
1107
- backup_exclusions: list[Path] = []
1108
- resolved_target: dict[str, str] | None = None
1109
-
1110
- try:
1111
- if not branch:
1112
- raise ValueError("Update file is missing the branch field.")
1113
- if not tag:
1114
- raise ValueError("Update file is missing the tag field.")
1115
-
1116
- stash_ref = create_rollback_stash(REPO_DIR, logger)
1117
-
1118
- if bool(request_data.get("backup_usr", True)):
1119
- backup_destination = create_usr_backup(
1120
- repo_dir=REPO_DIR,
1121
- backup_path=str(request_data.get("backup_path", "/root/update-backups")),
1122
- backup_name=str(request_data.get("backup_name", "agent-zero-usr-backup.zip")),
1123
- conflict_policy=str(request_data.get("backup_conflict_policy", "rename")),
1124
- logger=logger,
1125
- )
1126
- backup_zip_path = str(backup_destination)
1127
- backup_exclusions.append(backup_destination)
1128
-
1129
- resolved_target = resolve_requested_target(
1130
- REPO_DIR,
1131
- branch,
1132
- tag,
1133
- source_info["short_tag"],
1134
- logger,
1135
- )
1136
-
1137
- repository_changed = True
1138
- logger.log(
1139
- "Applying the requested release with native Git checkout. "
1140
- "Ignored files remain untouched; tracked files and non-ignored leftovers are replaced."
1141
- )
1142
- checkout_target_release(
1143
- REPO_DIR,
1144
- branch,
1145
- resolved_target["target_ref"],
1146
- resolved_target["target_description"],
1147
- logger,
1148
- exclude_paths=backup_exclusions,
1149
- )
1150
-
1151
- current_info = get_repo_version_info(REPO_DIR)
1152
- if resolved_target.get("expected_commit") and current_info["commit"] != resolved_target["expected_commit"]:
1153
- raise RuntimeError(
1154
- "Git checkout completed but the repository commit does not match the requested target. "
1155
- f"Expected {resolved_target['expected_commit']}, got {current_info['commit']}."
1156
- )
1157
- if resolved_target.get("expected_short_tag") and current_info["short_tag"] != resolved_target["expected_short_tag"]:
1158
- raise RuntimeError(
1159
- "Git checkout completed but the repository version does not match the requested tag. "
1160
- f"Expected {resolved_target['expected_short_tag']}, got {current_info['short_tag']}."
1161
- )
1162
-
1163
- updated_process = launch_ui_process(REPO_DIR, logger)
1164
- healthy, details = wait_for_health(
1165
- updated_process,
1166
- health_url=DEFAULT_HEALTH_URL,
1167
- timeout_seconds=DEFAULT_HEALTH_TIMEOUT_SECONDS,
1168
- poll_interval_seconds=DEFAULT_HEALTH_POLL_INTERVAL_SECONDS,
1169
- expected_version=resolved_target.get("expected_short_tag"),
1170
- expected_commit=resolved_target.get("expected_commit"),
1171
- logger=logger,
1172
- )
1173
- if healthy:
1174
- refresh_codex_cli(logger)
1175
- record_result(
1176
- status="success",
1177
- message=f"Updated Agent Zero to branch {branch}, {resolved_target['target_description']}.",
1178
- request_data=request_data,
1179
- source_info=source_info,
1180
- current_version=current_info["short_tag"],
1181
- started_at=started_at,
1182
- backup_zip_path=backup_zip_path,
1183
- rollback_applied=False,
1184
- )
1185
- if stash_ref:
1186
- logger.log(
1187
- f"Update succeeded, dropping temporary rollback stash {stash_ref}. "
1188
- "Tracked and non-ignored local changes were not reapplied."
1189
- )
1190
- try:
1191
- drop_stash(REPO_DIR, stash_ref, logger)
1192
- except Exception as exc:
1193
- logger.log(
1194
- f"Temporary rollback stash {stash_ref} could not be dropped automatically: {exc}"
1195
- )
1196
- return updated_process
1197
-
1198
- logger.log(f"Updated UI failed health check, rolling back: {details}")
1199
- terminate_process(updated_process)
1200
- restore_git_state(
1201
- REPO_DIR,
1202
- head=source_info["commit"],
1203
- branch=source_info.get("branch", ""),
1204
- logger=logger,
1205
- exclude_paths=backup_exclusions,
1206
- )
1207
- apply_stash(REPO_DIR, stash_ref or "", logger)
1208
- stash_ref = None
1209
-
1210
- rollback_process = launch_ui_process(REPO_DIR, logger)
1211
- rollback_healthy, rollback_details = wait_for_health(
1212
- rollback_process,
1213
- health_url=DEFAULT_HEALTH_URL,
1214
- timeout_seconds=DEFAULT_HEALTH_TIMEOUT_SECONDS,
1215
- poll_interval_seconds=DEFAULT_HEALTH_POLL_INTERVAL_SECONDS,
1216
- expected_version=source_info["short_tag"],
1217
- logger=logger,
1218
- )
1219
-
1220
- if rollback_healthy:
1221
- record_result(
1222
- status="rolled_back",
1223
- message=(
1224
- "Updated version failed its health check and the previous version was restored. "
1225
- f"Reason: {details}"
1226
- ),
1227
- request_data=request_data,
1228
- source_info=source_info,
1229
- current_version=source_info["short_tag"],
1230
- started_at=started_at,
1231
- backup_zip_path=backup_zip_path,
1232
- rollback_applied=True,
1233
- error=str(details),
1234
- )
1235
- return rollback_process
1236
-
1237
- terminate_process(rollback_process)
1238
- record_result(
1239
- status="rollback_failed",
1240
- message=(
1241
- "Updated version failed its health check and rollback also failed to become healthy."
1242
- ),
1243
- request_data=request_data,
1244
- source_info=source_info,
1245
- current_version=source_info["short_tag"],
1246
- started_at=started_at,
1247
- backup_zip_path=backup_zip_path,
1248
- rollback_applied=True,
1249
- error=f"Update error: {details}. Rollback error: {rollback_details}",
1250
- )
1251
- raise RuntimeError(str(rollback_details))
1252
- except Exception as exc:
1253
- restore_error = ""
1254
- if repository_changed or stash_ref:
1255
- logger.log(f"Restoring pre-update repository state after error: {exc}")
1256
- try:
1257
- restore_git_state(
1258
- REPO_DIR,
1259
- head=source_info["commit"],
1260
- branch=source_info.get("branch", ""),
1261
- logger=logger,
1262
- exclude_paths=backup_exclusions,
1263
- )
1264
- if stash_ref:
1265
- apply_stash(REPO_DIR, stash_ref, logger)
1266
- stash_ref = None
1267
- except Exception as restore_exc:
1268
- restore_error = str(restore_exc)
1269
- logger.log(f"Automatic restore failed: {restore_exc}")
1270
-
1271
- failure_message = str(exc)
1272
- if restore_error:
1273
- failure_message = f"{failure_message} | Restore error: {restore_error}"
1274
-
1275
- failure_status = "failed"
1276
- if repository_changed:
1277
- failure_status = "rollback_failed" if restore_error else "rolled_back"
1278
-
1279
- record_result(
1280
- status=failure_status,
1281
- message=failure_message,
1282
- request_data=request_data,
1283
- source_info=source_info,
1284
- current_version=source_info["short_tag"],
1285
- started_at=started_at,
1286
- backup_zip_path=backup_zip_path,
1287
- rollback_applied=repository_changed,
1288
- error=failure_message,
1289
- )
1290
- logger.log(f"Update flow failed: {failure_message}")
1291
- return launch_ui_process(REPO_DIR, logger)
1292
-
1293
-
1294
- def load_request_file() -> tuple[dict[str, Any] | None, str]:
1295
- if not TRIGGER_FILE.exists():
1296
- return None, ""
1297
- raw_text = TRIGGER_FILE.read_text(encoding="utf-8")
1298
- try:
1299
- loaded = yaml.safe_load(raw_text)
1300
- return (loaded if isinstance(loaded, dict) else None), raw_text
1301
- finally:
1302
- TRIGGER_FILE.unlink(missing_ok=True)
1303
-
1304
-
1305
- def queue_update_request(
1306
- *,
1307
- branch: str = "main",
1308
- tag: str = LATEST_SELECTOR_TAG,
1309
- backup_usr: bool = True,
1310
- backup_path: str = DEFAULT_BACKUP_DIR,
1311
- backup_name: str = "",
1312
- backup_conflict_policy: str = DEFAULT_BACKUP_CONFLICT_POLICY,
1313
- ) -> dict[str, Any]:
1314
- source_info = get_repo_version_info(REPO_DIR)
1315
- normalized_branch = (branch or "").strip().lower() or "main"
1316
- normalized_tag = normalize_requested_tag(tag)
1317
- normalized_policy = normalize_backup_conflict_policy(backup_conflict_policy)
1318
- normalized_backup_path = (backup_path or "").strip() or DEFAULT_BACKUP_DIR
1319
- normalized_backup_name = sanitize_filename(
1320
- backup_name,
1321
- build_default_backup_name(),
1322
- )
1323
-
1324
- payload = {
1325
- "branch": normalized_branch,
1326
- "tag": normalized_tag,
1327
- "source_version": source_info["short_tag"],
1328
- "source_describe": source_info["describe"],
1329
- "source_commit": source_info["commit"],
1330
- "requested_at": now_iso(),
1331
- "backup_usr": bool(backup_usr),
1332
- "backup_path": normalized_backup_path,
1333
- "backup_name": normalized_backup_name,
1334
- "backup_conflict_policy": normalized_policy,
1335
- }
1336
- write_yaml(TRIGGER_FILE, payload)
1337
- return payload
1338
-
1339
-
1340
- def installed_target_matches_request(
1341
- current_info: dict[str, str],
1342
- *,
1343
- requested_branch: str,
1344
- requested_tag: str,
1345
- ) -> bool:
1346
- normalized_tag = requested_tag.strip()
1347
- if not normalized_tag or is_latest_selector_tag(normalized_tag):
1348
- return False
1349
-
1350
- current_branch = current_info.get("branch", "").strip()
1351
- if requested_branch.strip() and current_branch != requested_branch.strip():
1352
- return False
1353
-
1354
- return current_info.get("describe", "").strip() == normalized_tag
1355
-
1356
-
1357
- def trigger_update_command(args: list[str]) -> int:
1358
- parser = argparse.ArgumentParser(
1359
- prog="trigger_self_update.sh",
1360
- description="Queue an Agent Zero self-update for the next startup attempt.",
1361
- )
1362
- parser.add_argument(
1363
- "branch",
1364
- nargs="?",
1365
- default="main",
1366
- help="Target official branch. Default: main",
1367
- )
1368
- parser.add_argument(
1369
- "tag",
1370
- nargs="?",
1371
- default=LATEST_SELECTOR_TAG,
1372
- help='Target release tag such as v1.10 or "latest". Default: latest',
1373
- )
1374
- parser.add_argument(
1375
- "--backup-dir",
1376
- default=DEFAULT_BACKUP_DIR,
1377
- help=f"Directory for the usr backup zip. Default: {DEFAULT_BACKUP_DIR}",
1378
- )
1379
- parser.add_argument(
1380
- "--backup-name",
1381
- default="",
1382
- help="Backup zip filename. Default: autogenerated usr-YYYYMMDD-HHMMSS.zip",
1383
- )
1384
- parser.add_argument(
1385
- "--backup-conflict-policy",
1386
- default=DEFAULT_BACKUP_CONFLICT_POLICY,
1387
- choices=sorted(BACKUP_CONFLICT_POLICIES),
1388
- help="How to handle an existing backup zip. Default: rename",
1389
- )
1390
- parser.add_argument(
1391
- "--no-backup",
1392
- action="store_true",
1393
- help="Skip creating a usr backup before the update.",
1394
- )
1395
- parsed = parser.parse_args(args)
1396
-
1397
- try:
1398
- payload = queue_update_request(
1399
- branch=parsed.branch,
1400
- tag=parsed.tag,
1401
- backup_usr=not parsed.no_backup,
1402
- backup_path=parsed.backup_dir,
1403
- backup_name=parsed.backup_name,
1404
- backup_conflict_policy=parsed.backup_conflict_policy,
1405
- )
1406
- except Exception as exc:
1407
- print(f"Failed to queue self-update: {exc}", file=sys.stderr)
1408
- return 1
1409
-
1410
- print("Queued Agent Zero self-update for the next startup attempt.")
1411
- print(f"Branch: {payload['branch']}")
1412
- print(f"Version: {payload['tag']}")
1413
- if payload["backup_usr"]:
1414
- print(f"Backup dir: {payload['backup_path']}")
1415
- print(f"Backup name: {payload['backup_name']}")
1416
- print(f"Backup conflict policy: {payload['backup_conflict_policy']}")
1417
- else:
1418
- print("Backup: disabled")
1419
- print(f"Trigger file: {TRIGGER_FILE}")
1420
- print(f"Log file: {LOG_FILE}")
1421
- print("Restart the container or Agent Zero process to apply it.")
1422
- return 0
1423
-
1424
-
1425
- def docker_run_ui() -> int:
1426
- request_data, raw_text = load_request_file()
1427
- logger = AttemptLogger(LOG_FILE)
1428
- quiet_logger = NullLogger()
1429
-
1430
- if request_data:
1431
- logger.reset()
1432
- logger.log(f"Consumed update file at {TRIGGER_FILE}")
1433
- logger.log_block("Trigger file content", raw_text)
1434
- clean_uv_cache(logger)
1435
- try:
1436
- clean_transient_desktop_agent_state(REPO_DIR, logger)
1437
- except Exception as exc:
1438
- logger.log(f"Transient desktop agent cleanup skipped after error: {exc}")
1439
-
1440
- try:
1441
- current = get_repo_version_info(REPO_DIR)
1442
- requested_branch = str(request_data.get("branch", "")).strip()
1443
- requested_tag = str(request_data.get("tag", "")).strip()
1444
- if installed_target_matches_request(
1445
- current,
1446
- requested_branch=requested_branch,
1447
- requested_tag=requested_tag,
1448
- ):
1449
- logger.log(
1450
- "Requested tag already matches the installed version, skipping file replacement."
1451
- )
1452
- refresh_codex_cli(logger)
1453
- record_result(
1454
- status="skipped",
1455
- message="Requested tag already matches the installed version.",
1456
- request_data=request_data,
1457
- source_info=current,
1458
- current_version=current["short_tag"],
1459
- started_at=now_iso(),
1460
- rollback_applied=False,
1461
- )
1462
- process = launch_ui_process(REPO_DIR, logger)
1463
- else:
1464
- process = execute_pending_update(request_data, logger=logger)
1465
- except Exception as exc:
1466
- logger.log(f"Self-update bootstrap failed unexpectedly: {exc}")
1467
- process = launch_ui_process(REPO_DIR, logger)
1468
- elif raw_text:
1469
- logger.reset()
1470
- logger.log(f"Consumed invalid update file at {TRIGGER_FILE}")
1471
- logger.log_block("Trigger file content", raw_text)
1472
- source_info = get_repo_version_info(REPO_DIR)
1473
- record_result(
1474
- status="failed",
1475
- message="Update file was not valid YAML.",
1476
- request_data={},
1477
- source_info=source_info,
1478
- current_version=source_info["short_tag"],
1479
- started_at=now_iso(),
1480
- rollback_applied=False,
1481
- error="Update file was not valid YAML.",
1482
- )
1483
- process = launch_ui_process(REPO_DIR, logger)
1484
- else:
1485
- process = launch_ui_process(REPO_DIR, quiet_logger)
1486
-
1487
- return wait_for_process(process)
1488
-
1489
-
1490
- def main(argv: list[str] | None = None) -> int:
1491
- args = list(argv if argv is not None else sys.argv[1:])
1492
- if not args or args[0] == "docker-run-ui":
1493
- return docker_run_ui()
1494
- if args[0] == "trigger-update":
1495
- return trigger_update_command(args[1:])
1496
- if args[0] == "refresh-codex":
1497
- refresh_codex_cli(AttemptLogger(LOG_FILE))
1498
- return 0
1499
- if args[0] in {"-h", "--help"}:
1500
- print("Usage: self_update_manager.py [docker-run-ui | trigger-update ... | refresh-codex]")
1501
- return 0
1502
- print(f"Unknown command: {args[0]}", file=sys.stderr)
1503
- return 1
1504
-
1505
-
1506
- if __name__ == "__main__":
1507
- raise SystemExit(main())
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:f382c6ca87739be6bd9353616a6edc05a4eeaa0e02a6b7f970cb9f5ee25d90b4
3
+ size 50698
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
docker/run/fs/exe/supervisor_event_listener.py CHANGED
@@ -1,47 +1,3 @@
1
- #!/usr/bin/python
2
- import sys
3
- import os
4
- import logging
5
- import subprocess
6
- import time
7
-
8
- from supervisor.childutils import listener # type: ignore
9
-
10
-
11
- def main(args):
12
- logging.basicConfig(stream=sys.stderr, level=logging.DEBUG, format='%(asctime)s %(levelname)s %(filename)s: %(message)s')
13
- logger = logging.getLogger("supervisord-watchdog")
14
- debug_mode = True if 'DEBUG' in os.environ else False
15
-
16
- while True:
17
- logger.info("Listening for events...")
18
- headers, body = listener.wait(sys.stdin, sys.stdout)
19
- body = dict([pair.split(":") for pair in body.split(" ")])
20
-
21
- logger.debug("Headers: %r", repr(headers))
22
- logger.debug("Body: %r", repr(body))
23
- logger.debug("Args: %r", repr(args))
24
-
25
- if debug_mode:
26
- continue
27
-
28
- try:
29
- if headers["eventname"] == "PROCESS_STATE_FATAL":
30
- logger.info("Process entered FATAL state...")
31
- if not args or body["processname"] in args:
32
- logger.error("Killing off supervisord instance ...")
33
- _ = subprocess.call(["/bin/kill", "-15", "1"], stdout=sys.stderr)
34
- logger.info("Sent TERM signal to init process")
35
- time.sleep(5)
36
- logger.critical("Why am I still alive? Send KILL to all processes...")
37
- _ = subprocess.call(["/bin/kill", "-9", "-1"], stdout=sys.stderr)
38
- except Exception as e:
39
- logger.critical("Unexpected Exception: %s", str(e))
40
- listener.fail(sys.stdout)
41
- exit(1)
42
- else:
43
- listener.ok(sys.stdout)
44
-
45
-
46
- if __name__ == '__main__':
47
- main(sys.argv[1:])
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:9ff1c038b17944bf5b5d77ce5cce96fde37553a57700f13369716a39250ebb35
3
+ size 1670
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
docker/run/fs/exe/trigger_self_update.sh CHANGED
@@ -1,6 +1,3 @@
1
- #!/bin/sh
2
- set -eu
3
-
4
- SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
5
-
6
- exec python3 "$SCRIPT_DIR/self_update_manager.py" trigger-update "$@"
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:4d011f44c92f138c0fdc4042fd04bd396f19796a11731b1ed3d5357722ee19fd
3
+ size 146
 
 
 
docker/run/fs/ins/copy_A0.sh CHANGED
@@ -1,12 +1,3 @@
1
- #!/bin/bash
2
- set -e
3
-
4
- # Paths
5
- SOURCE_DIR="/git/agent-zero"
6
- TARGET_DIR="/a0"
7
-
8
- # Copy repository files if run_ui.py is missing in /a0 (if the volume is mounted)
9
- if [ ! -f "$TARGET_DIR/run_ui.py" ]; then
10
- echo "Copying files from $SOURCE_DIR to $TARGET_DIR..."
11
- cp -rn --no-preserve=ownership,mode "$SOURCE_DIR/." "$TARGET_DIR"
12
- fi
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:bb5bc666dfb5c75d664be6c2e87a547016b36c68d821c583be59dd3168009041
3
+ size 331
 
 
 
 
 
 
 
 
 
docker/run/fs/ins/install_A0.sh CHANGED
@@ -1,44 +1,3 @@
1
- #!/bin/bash
2
- set -e
3
-
4
- # Exit immediately if a command exits with a non-zero status.
5
- # set -e
6
-
7
- # branch from parameter
8
- if [ -z "$1" ]; then
9
- echo "Error: Branch parameter is empty. Please provide a valid branch name."
10
- exit 1
11
- fi
12
- BRANCH="$1"
13
-
14
- if [ "$BRANCH" = "local" ]; then
15
- # For local branch, use the files
16
- echo "Using local dev files in /git/agent-zero"
17
- # List all files recursively in the target directory
18
- # echo "All files in /git/agent-zero (recursive):"
19
- # find "/git/agent-zero" -type f | sort
20
- else
21
- # For other branches, clone from GitHub
22
- echo "Cloning repository from branch $BRANCH..."
23
- git clone -b "$BRANCH" "https://github.com/agent0ai/agent-zero" "/git/agent-zero" || {
24
- echo "CRITICAL ERROR: Failed to clone repository. Branch: $BRANCH"
25
- exit 1
26
- }
27
- fi
28
-
29
- . "/ins/setup_venv.sh" "$@"
30
-
31
- # moved to base image
32
- # # Ensure the virtual environment and pip setup
33
- # pip install --upgrade pip ipython requests
34
- # # Install some packages in specific variants
35
- # pip install torch --index-url https://download.pytorch.org/whl/cpu
36
-
37
- # Install remaining A0 python packages
38
- uv pip install -r /git/agent-zero/requirements.txt
39
-
40
- # install playwright
41
- bash /ins/install_playwright.sh "$@"
42
-
43
- # Preload A0
44
- python /git/agent-zero/preload.py --dockerized=true
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:02ac5d3e1c0f33de9956752ae32225e90eccc087e7307c6e0d40056604448622
3
+ size 1294
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
docker/run/fs/ins/install_A02.sh CHANGED
@@ -1,17 +1,3 @@
1
- #!/bin/bash
2
- set -e
3
-
4
- # cachebuster script, this helps speed up docker builds
5
-
6
- # remove repo (if not local branch)
7
- if [ "$1" != "local" ]; then
8
- rm -rf /git/agent-zero
9
- fi
10
-
11
- # run the original install script again
12
- bash /ins/install_A0.sh "$@"
13
-
14
- # remove python packages cache
15
- . "/ins/setup_venv.sh" "$@"
16
- pip cache purge
17
- uv cache prune
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:fd65145eed86f46ad4c83ef95ff1710bb213fc8b2f3c010210d8c1a1364e2576
3
+ size 332
 
 
 
 
 
 
 
 
 
 
 
 
 
 
docker/run/fs/ins/install_additional.sh CHANGED
@@ -1,94 +1,3 @@
1
- #!/bin/bash
2
- set -e
3
-
4
- # install playwright - moved to install A0
5
- # bash /ins/install_playwright.sh "$@"
6
-
7
- # searxng - moved to base image
8
- # bash /ins/install_searxng.sh "$@"
9
-
10
- if ! command -v apt-get >/dev/null 2>&1; then
11
- echo "apt-get unavailable; skipping LibreOffice install"
12
- exit 0
13
- fi
14
-
15
- KALI_SUITE="kali-last-snapshot"
16
- LIBREOFFICE_VERSION="4:26.2.4.2-1"
17
- XPRA_VERSION="6.5.2-r0-1"
18
- arch="$(dpkg --print-architecture)"
19
-
20
- XPRA_HTML5_VERSION="19-r1-1"
21
- if [ "$arch" = "arm64" ]; then
22
- XPRA_HTML5_VERSION="21-r1-1"
23
- fi
24
-
25
- LIBREOFFICE_PACKAGES=(
26
- "libreoffice-core=$LIBREOFFICE_VERSION"
27
- "libreoffice-writer=$LIBREOFFICE_VERSION"
28
- "libreoffice-calc=$LIBREOFFICE_VERSION"
29
- "libreoffice-impress=$LIBREOFFICE_VERSION"
30
- "libreoffice-gtk3=$LIBREOFFICE_VERSION"
31
- "python3-uno=$LIBREOFFICE_VERSION"
32
- )
33
- XPRA_PACKAGES=(
34
- "xpra-common=$XPRA_VERSION"
35
- "xpra-server=$XPRA_VERSION"
36
- "xpra-client=$XPRA_VERSION"
37
- "xpra-client-gtk3=$XPRA_VERSION"
38
- "xpra-x11=$XPRA_VERSION"
39
- "xpra-html5=$XPRA_HTML5_VERSION"
40
- )
41
-
42
- apt-get update
43
- ATK_VERSION="$(dpkg-query -W -f='${Version}' libatk1.0-0t64)"
44
- ATK_GIR_PACKAGE="/tmp/gir1.2-atk-1.0_${ATK_VERSION}_${arch}.deb"
45
- (cd /tmp && apt-get download "gir1.2-atk-1.0=$ATK_VERSION")
46
-
47
- for source in /etc/apt/sources.list /etc/apt/sources.list.d/kali.sources; do
48
- [ ! -f "$source" ] || sed -i "s/kali-rolling/$KALI_SUITE/g" "$source"
49
- done
50
-
51
- apt-get update
52
- DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends ca-certificates wget
53
- wget -O /usr/share/keyrings/xpra.asc https://xpra.org/xpra.asc
54
- cat >/etc/apt/sources.list.d/xpra.sources <<EOF
55
- Types: deb
56
- URIs: https://xpra.org
57
- Suites: trixie
58
- Components: main
59
- Signed-By: /usr/share/keyrings/xpra.asc
60
- Architectures: $arch
61
- EOF
62
- apt-get update
63
- DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
64
- "$ATK_GIR_PACKAGE" \
65
- gir1.2-gtk-3.0 \
66
- "${LIBREOFFICE_PACKAGES[@]}" \
67
- "${XPRA_PACKAGES[@]}" \
68
- xfce4-session \
69
- xfwm4 \
70
- xfce4-panel \
71
- xfdesktop4 \
72
- xfce4-settings \
73
- thunar \
74
- gvfs \
75
- libglib2.0-bin \
76
- xfce4-terminal \
77
- x11-xserver-utils \
78
- x11-utils \
79
- x11-apps \
80
- xdotool \
81
- xclip \
82
- xauth \
83
- xvfb \
84
- dbus-x11 \
85
- fonts-dejavu \
86
- fonts-liberation \
87
- fonts-crosextra-caladea \
88
- fonts-crosextra-carlito \
89
- fonts-noto-core \
90
- fonts-noto-cjk \
91
- fonts-noto-color-emoji
92
-
93
- rm -f "$ATK_GIR_PACKAGE"
94
- rm -rf /var/lib/apt/lists/*
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:a9d95cfdeef8d7b0fd8f21cce0662d06b047b914dbc294fb7e90d43ce7cc193f
3
+ size 2351
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
docker/run/fs/ins/install_playwright.sh CHANGED
@@ -1,13 +1,3 @@
1
- #!/bin/bash
2
- set -e
3
-
4
- # activate venv
5
- . "/ins/setup_venv.sh" "$@"
6
-
7
- # set PW installation path to temporary Browser runtime storage
8
- export PLAYWRIGHT_BROWSERS_PATH=/a0/tmp/playwright
9
- mkdir -p "$PLAYWRIGHT_BROWSERS_PATH"
10
-
11
- # preinstall Chromium for fresh images; the Browser hook also reconciles self-updated installs
12
- apt-get install -y fonts-unifont libnss3 libnspr4 libatk1.0-0 libatspi2.0-0 libxcomposite1 libxdamage1 libatk-bridge2.0-0 libcups2
13
- patchright install chromium --no-shell
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:b9658612a888db9185d04b10ec494610ee8815f6f2af2150bd8af7626d4ebf6d
3
+ size 483
 
 
 
 
 
 
 
 
 
 
docker/run/fs/ins/post_install.sh CHANGED
@@ -1,6 +1,3 @@
1
- #!/bin/bash
2
- set -e
3
-
4
- # Cleanup package list
5
- rm -rf /var/lib/apt/lists/*
6
- apt-get clean
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:0376af94660898f1c53428fe141a801baf201c5384503b91f0f86f776ebb4245
3
+ size 84
 
 
 
docker/run/fs/ins/pre_install.sh CHANGED
@@ -1,13 +1,3 @@
1
- #!/bin/bash
2
- set -e
3
-
4
- # update apt
5
- apt-get update
6
-
7
- # fix permissions for cron files if any
8
- if [ -f /etc/cron.d/* ]; then
9
- chmod 0644 /etc/cron.d/*
10
- fi
11
-
12
- # Prepare SSH daemon
13
- bash /ins/setup_ssh.sh "$@"
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:6763aa5590db64648382903da34388531630c711c7cd58c84735746b6c97cce9
3
+ size 201
 
 
 
 
 
 
 
 
 
 
docker/run/fs/ins/setup_ssh.sh CHANGED
@@ -1,7 +1,3 @@
1
- #!/bin/bash
2
- set -e
3
-
4
- # Set up SSH
5
- mkdir -p /var/run/sshd && \
6
- # echo 'root:toor' | chpasswd && \
7
- sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:838d4044464ff4dbcbf09a1d05e16189a5678963283591bee446a37a37c984f9
3
+ size 191
 
 
 
 
docker/run/fs/ins/setup_venv.sh CHANGED
@@ -1,12 +1,3 @@
1
- #!/bin/bash
2
- set -e
3
-
4
- # this has to be ready from base image
5
- # if [ ! -d /opt/venv ]; then
6
- # # Create and activate Python virtual environment
7
- # python3.12 -m venv /opt/venv
8
- # source /opt/venv/bin/activate
9
- # else
10
- # source /opt/venv/bin/activate
11
- # fi
12
- source /opt/venv-a0/bin/activate
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:ad753d8637f7cd7b0186bc012434f2ce4834c62942b032d1b93a0facd2b7eed2
3
+ size 295
 
 
 
 
 
 
 
 
 
docker/run/fs/per/root/.bashrc CHANGED
@@ -1,9 +1,3 @@
1
- # .bashrc
2
-
3
- # Source global definitions
4
- if [ -f /etc/bashrc ]; then
5
- . /etc/bashrc
6
- fi
7
-
8
- # Activate the virtual environment
9
- source /opt/venv/bin/activate
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:d29ad830f8c27e14002e059df2bd7a57138cf59e109e492b9727a3226f86573a
3
+ size 154
 
 
 
 
 
 
docker/run/fs/per/root/.profile CHANGED
@@ -1,9 +1,3 @@
1
- # .bashrc
2
-
3
- # Source global definitions
4
- if [ -f /etc/bashrc ]; then
5
- . /etc/bashrc
6
- fi
7
-
8
- # Activate the virtual environment
9
- source /opt/venv/bin/activate
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:d29ad830f8c27e14002e059df2bd7a57138cf59e109e492b9727a3226f86573a
3
+ size 154
 
 
 
 
 
 
docs/AGENTS.md CHANGED
@@ -1,35 +1,3 @@
1
- # Documentation DOX
2
-
3
- ## Purpose
4
-
5
- - Own human-facing documentation, screenshots, setup guides, developer guides, and documentation assets.
6
- - Keep docs accurate to current source behavior and practical user workflows.
7
-
8
- ## Ownership
9
-
10
- - `README.md`, `quickstart.md`, `guides/`, and `setup/` cover user-facing setup and workflows.
11
- - `developer/` covers compact developer references and source handoffs.
12
- - `plans/` covers implementation plans, migration notes, and staged technical roadmaps.
13
- - `res/` contains documentation images and other documentation assets.
14
-
15
- ## Local Contracts
16
-
17
- - Prefer local docs for practical workflows and direct users to DeepWiki for source-linked internals when appropriate.
18
- - Do not document secrets, private deployment details, unreleased credentials, or user-specific runtime state.
19
- - Screenshots and assets must be relevant to the documented UI state and should be updated when UI changes make them misleading.
20
- - Keep links relative inside the docs tree unless they intentionally point to external community or reference resources.
21
-
22
- ## Work Guidance
23
-
24
- - Update docs in the same change when user-visible behavior, setup steps, settings names, plugin workflows, or UI labels change.
25
- - Keep user guides task-oriented and avoid duplicating architecture contracts already owned by source-adjacent DOX files.
26
- - When editing screenshots or binary assets, avoid unrelated metadata churn.
27
-
28
- ## Verification
29
-
30
- - Check changed internal links manually or with an available link checker.
31
- - For setup or Docker docs, verify commands against current scripts and Docker files.
32
-
33
- ## Child DOX Index
34
-
35
- No child DOX files.
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:e058179b520b1f87231b052f58d4e250898631afc13d41c78adf72de691b9126
3
+ size 1625
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
docs/README.md CHANGED
@@ -1,159 +1,3 @@
1
- ![Agent Zero Logo](res/header.png)
2
- # Agent Zero Documentation
3
-
4
- Welcome to the Agent Zero documentation hub. Start with the practical guides
5
- below: install it, open the Web UI, connect your host machine when needed, and
6
- learn the main workflows by sight.
7
-
8
- For architecture and source-linked internals, use
9
- [DeepWiki for Agent Zero](https://deepwiki.com/agent0ai/agent-zero). The local
10
- docs focus on practical setup, screenshots, and user workflows.
11
-
12
- ## Quick Start
13
-
14
- - **[Quickstart Guide](quickstart.md):** Get up and running in 5 minutes with Agent Zero.
15
- - **[Agent Zero Launcher](guides/launcher.md):** Use the desktop app to set up Docker, install Agent Zero, open Instances, or connect a remote Instance.
16
- - **[First-Run Onboarding](guides/onboarding.md):** Choose Cloud, AI account, or Local access, then select main and utility models.
17
- - **[Installation Guide](setup/installation.md):** A0 Launcher downloads, A0 Install, direct Docker, updates, and advanced Docker setup (includes [How to Update](setup/installation.md#how-to-update-agent-zero)).
18
- - **[A0 CLI Connector](guides/a0-cli-connector.md):** Install the host connector for a running Agent Zero instance, use the command palette, and switch Browser modes.
19
- - **[Self Update](guides/self-update.md):** How the in-app updater works (technical reference).
20
- - **[VPS Deployment](setup/vps-deployment.md):** Deploy Agent Zero on a remote server.
21
- - **[Development Setup](setup/dev-setup.md):** Set up a local development environment.
22
-
23
- ## User Guides
24
-
25
- - **[Usage Guide](guides/usage.md):** Practical tour of Agent Zero's main workflows.
26
- - **[Agent Zero Launcher](guides/launcher.md):** Fresh-machine Launcher walkthrough, Docker setup gate, Installs, Instances, and docs screenshot capture with Playwright/Electron.
27
- - **[First-Run Onboarding](guides/onboarding.md):** Set up OpenRouter, our proxy API or another provider with the guided wizard.
28
- - **[Browser Guide](guides/browser.md):** Use the built-in Browser, live Canvas surface, annotations, screenshots, host browser mode, and extensions.
29
- - **[Desktop Guide](guides/desktop.md):** Use the built-in Linux desktop, GUI apps, and LibreOffice Writer/Calc/Impress Cowork.
30
- - **[A0 CLI Connector](guides/a0-cli-connector.md):** Terminal-first host connector for Agent Zero, with screenshots of the host picker, connected shell, command palette, and Browser modes.
31
- - **[Create a Small Plugin](guides/create-plugin.md):** Build and review a tiny Web UI plugin that adds an unread dot to the chat list.
32
- - **[Skills Guide](guides/skills.md):** Open the Skills selector, add active skills, and remove prompt protocol entries you no longer need.
33
- - **[Agent Profiles](guides/agent-profiles.md):** Create and manage profiles in Easy or Advanced mode, set project availability, and control Tool, MCP, and Skill access.
34
- - **[Model Presets](guides/model-presets.md):** Create simple named shortcuts for model setups.
35
- - **[Memory Guide](guides/memory.md):** Search, edit, delete, and curate memories so useful context does not become stale noise.
36
- - **[Projects Tutorial](guides/projects.md):** Learn to create isolated workspaces with dedicated context and memory.
37
- - **[API Integration](guides/api-integration.md):** Add external APIs without writing code.
38
- - **[MCP Setup](guides/mcp-setup.md):** Configure Model Context Protocol servers.
39
- - **[A2A Setup](guides/a2a-setup.md):** Enable agent-to-agent communication.
40
- - **[Troubleshooting](guides/troubleshooting.md):** Solutions to common issues and FAQs.
41
-
42
- ## Technical Reference
43
-
44
- - **[DeepWiki for Agent Zero](https://deepwiki.com/agent0ai/agent-zero):** Architecture, Web UI internals, plugin lifecycle, backend APIs, deployment details, and source-linked explanations.
45
- - **[Architecture](developer/architecture.md):** Short local handoff to DeepWiki plus practical starting points.
46
- - **[Plugins](developer/plugins.md):** Compact plugin starting points and sharing checklist.
47
- - **[Extensions](developer/extensions.md):** Short guide for when an extension is the right tool.
48
- - **[Connectivity](developer/connectivity.md):** Choose between A0 CLI, MCP, A2A, and external APIs.
49
- - **[WebSockets](developer/websockets.md):** Short local handoff to DeepWiki and source files.
50
- - **[MCP Configuration](developer/mcp-configuration.md):** Compact reference for MCP JSON.
51
- - **[Notifications](developer/notifications.md):** Notification system architecture and setup.
52
- - **[Contributing Skills](developer/contributing-skills.md):** Create and share agent skills.
53
- - **[Contributing Guide](guides/contribution.md):** Contribute to the Agent Zero project.
54
-
55
- ## Community & Support
56
-
57
- - **Join the Community:** Connect with other users on [Discord](https://discord.gg/B8KZKNsPpj) to discuss ideas, ask questions, and collaborate.
58
- - **Share Your Work:** Show off your Agent Zero creations and workflows in the [Show and Tell](https://github.com/agent0ai/agent-zero/discussions/categories/show-and-tell) area.
59
- - **Report Issues:** Use the [GitHub issue tracker](https://github.com/agent0ai/agent-zero/issues) to report bugs or suggest features.
60
- - **Follow Updates:** Subscribe to the [YouTube channel](https://www.youtube.com/@AgentZeroFW) for tutorials and release videos.
61
-
62
- ---
63
-
64
- ## Table of Contents
65
-
66
- - [Quick Start](#quick-start)
67
- - [Quickstart Guide](quickstart.md)
68
- - [Agent Zero Launcher](guides/launcher.md)
69
- - [First-Run Onboarding](guides/onboarding.md)
70
- - [Installation Guide](setup/installation.md)
71
- - [How to Update Agent Zero](setup/installation.md#how-to-update-agent-zero)
72
- - [Manual Installation (Advanced)](setup/installation.md#manual-installation-advanced)
73
- - [Step 1: Install Docker Desktop](setup/installation.md#step-1-install-docker-desktop)
74
- - [Windows Installation](setup/installation.md#windows-installation)
75
- - [macOS Installation](setup/installation.md#macos-installation)
76
- - [Linux Installation](setup/installation.md#linux-installation)
77
- - [Step 2: Run Agent Zero](setup/installation.md#step-2-run-agent-zero)
78
- - [Pull Docker Image](setup/installation.md#21-pull-the-agent-zero-docker-image)
79
- - [Map Folders for Persistence](setup/installation.md#22-optional-map-folders-for-persistence)
80
- - [Run the Container](setup/installation.md#23-run-the-container)
81
- - [Access the Web UI](setup/installation.md#24-access-the-web-ui)
82
- - [Step 3: Configure Agent Zero](setup/installation.md#step-3-configure-agent-zero)
83
- - [Settings Configuration](setup/installation.md#settings-configuration)
84
- - [Agent Configuration](setup/installation.md#agent-configuration)
85
- - [Chat Model Settings](setup/installation.md#chat-model-settings)
86
- - [API Keys](setup/installation.md#api-keys)
87
- - [Authentication](setup/installation.md#authentication)
88
- - [Choosing Your LLMs](setup/installation.md#choosing-your-llms)
89
- - [Installing Ollama (Local Models)](setup/installation.md#installing-and-using-ollama-local-models)
90
- - [Using on Mobile Devices](setup/installation.md#using-agent-zero-on-your-mobile-device)
91
- - [Self Update (technical)](guides/self-update.md)
92
- - [VPS Deployment](setup/vps-deployment.md)
93
- - [Development Setup](setup/dev-setup.md)
94
- - [A0 CLI Connector](guides/a0-cli-connector.md)
95
-
96
- - [User Guides](#user-guides)
97
- - [Usage Guide](guides/usage.md)
98
- - [Basic Operations](guides/usage.md#basic-operations)
99
- - [Plugins And Plugin Hub](guides/usage.md#plugins-and-plugin-hub)
100
- - [Skills, Agent Profiles, And Model Presets](guides/usage.md#skills-agent-profiles-and-model-presets)
101
- - [Skills](guides/usage.md#skills)
102
- - [Agent Profiles](guides/usage.md#agent-profiles)
103
- - [Model Presets](guides/usage.md#model-presets)
104
- - [File Attachments](guides/usage.md#file-attachments)
105
- - [Tool Usage](guides/usage.md#tool-usage)
106
- - [Browser Tool And Surface](guides/usage.md#browser-tool-and-surface)
107
- - [Desktop Surface](guides/usage.md#desktop-surface)
108
- - [Agent-To-Agent Communication](guides/usage.md#agent-to-agent-communication)
109
- - [Multi-Agent Cooperation](guides/usage.md#multi-agent-cooperation)
110
- - [Projects](guides/usage.md#projects)
111
- - [Tasks And Scheduling](guides/usage.md#tasks-and-scheduling)
112
- - [Secrets And Variables](guides/usage.md#secrets-and-variables)
113
- - [Remote Access Via Tunneling](guides/usage.md#remote-access-via-tunneling)
114
- - [Voice Interface](guides/usage.md#voice-interface)
115
- - [Mathematical Expressions](guides/usage.md#mathematical-expressions)
116
- - [File Browser](guides/usage.md#file-browser)
117
- - [Memory Management](guides/usage.md#memory-management)
118
- - [Backup And Restore](guides/usage.md#backup-and-restore)
119
- - [Agent Zero Launcher](guides/launcher.md)
120
- - [Browser Guide](guides/browser.md)
121
- - [Desktop Guide](guides/desktop.md)
122
- - [A0 CLI Connector](guides/a0-cli-connector.md)
123
- - [Create a Small Plugin](guides/create-plugin.md)
124
- - [Skills Guide](guides/skills.md)
125
- - [Agent Profiles](guides/agent-profiles.md)
126
- - [Model Presets](guides/model-presets.md)
127
- - [Memory Guide](guides/memory.md)
128
- - [Projects Tutorial](guides/projects.md)
129
- - [API Integration](guides/api-integration.md)
130
- - [MCP Setup](guides/mcp-setup.md)
131
- - [A2A Setup](guides/a2a-setup.md)
132
- - [Troubleshooting](guides/troubleshooting.md)
133
-
134
- - [Technical Reference](#technical-reference)
135
- - [DeepWiki for Agent Zero](https://deepwiki.com/agent0ai/agent-zero)
136
- - [Architecture](developer/architecture.md)
137
- - [Plugins](developer/plugins.md)
138
- - [Extensions](developer/extensions.md)
139
- - [Connectivity](developer/connectivity.md)
140
- - [WebSockets](developer/websockets.md)
141
- - [MCP Configuration](developer/mcp-configuration.md)
142
- - [Notifications](developer/notifications.md)
143
- - [Contributing Skills](developer/contributing-skills.md)
144
- - [Contributing Guide](guides/contribution.md)
145
-
146
- ---
147
-
148
- ## Documentation Ownership
149
-
150
- | Content type | Home |
151
- | --- | --- |
152
- | Setup, screenshots, and everyday workflows | These docs |
153
- | Architecture and source-linked internals | [DeepWiki](https://deepwiki.com/agent0ai/agent-zero) |
154
- | Exact behavior | The current source code |
155
- | Community help and examples | Discord, Skool, GitHub discussions |
156
-
157
- ### Your journey with Agent Zero starts now!
158
-
159
- Ready to dive in? Start with the [Quickstart Guide](quickstart.md) for the fastest path to your first chat, or follow the [Installation Guide](setup/installation.md) for a detailed setup walkthrough.
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:5acb9756eca09fa8de40d237bfead984b1071ee24a9838bfb0c8fd3ca24f6f8b
3
+ size 10383
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
docs/developer/architecture.md CHANGED
@@ -1,32 +1,3 @@
1
- # Architecture
2
-
3
- Agent Zero architecture is now documented in
4
- [DeepWiki for Agent Zero](https://deepwiki.com/agent0ai/agent-zero).
5
-
6
- Use DeepWiki when you want source-linked explanations of:
7
-
8
- - the agent loop and message flow;
9
- - Web UI internals;
10
- - plugin discovery and lifecycle;
11
- - projects, memory, tools, and scheduler internals;
12
- - backend APIs and WebSocket behavior;
13
- - deployment and runtime structure.
14
-
15
- This local page intentionally stays short so the repository does not maintain a
16
- second, stale architecture manual.
17
-
18
- ## Practical Starting Points
19
-
20
- | Goal | Start here |
21
- | --- | --- |
22
- | Install or update Agent Zero | [Installation Guide](../setup/installation.md) |
23
- | Learn the Web UI | [Usage Guide](../guides/usage.md) |
24
- | Create a focused workspace | [Projects Guide](../guides/projects.md) |
25
- | Use the Browser | [Browser Guide](../guides/browser.md) |
26
- | Connect host files and shell | [A0 CLI Connector](../guides/a0-cli-connector.md) |
27
- | Build plugins | [Plugins](plugins.md) |
28
- | Build extensions | [Extensions](extensions.md) |
29
- | Configure MCP | [MCP Configuration](mcp-configuration.md) |
30
-
31
- If you are changing core behavior, read the relevant DeepWiki page first, then
32
- inspect the source in this repository before editing.
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:fe7e91408016bf1d7d6e1c172a5beadb9681e62e7522231fbfebbb04fc9c40c5
3
+ size 1235
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
docs/developer/connectivity.md CHANGED
@@ -1,55 +1,3 @@
1
- # Connectivity
2
-
3
- This page helps you choose the right connection path.
4
-
5
- For source-linked architecture and endpoint internals, use
6
- [DeepWiki for Agent Zero](https://deepwiki.com/agent0ai/agent-zero). The local
7
- docs should not duplicate the full connectivity architecture.
8
-
9
- ## Choose The Right Path
10
-
11
- | Need | Start here |
12
- | --- | --- |
13
- | Let Agent Zero work on your host files, shell, or browser | [A0 CLI Connector](../guides/a0-cli-connector.md) |
14
- | Add a third-party tool through MCP | [MCP Setup](../guides/mcp-setup.md) |
15
- | Let another agent talk to Agent Zero | [A2A Setup](../guides/a2a-setup.md) |
16
- | Add an external API for one workflow | [API Integration](../guides/api-integration.md) |
17
- | Study API, MCP, or A2A internals | [DeepWiki](https://deepwiki.com/agent0ai/agent-zero) |
18
-
19
- ## External API Basics
20
-
21
- You can find your API token in Agent Zero under **Settings > External Services**.
22
-
23
- Common external endpoints include:
24
-
25
- | Endpoint | Use it for |
26
- | --- | --- |
27
- | `POST /api_message` | Send a message to Agent Zero. |
28
- | `GET/POST /api_log_get` | Read chat logs. |
29
- | `POST /api_terminate_chat` | Stop a running chat. |
30
- | `POST /api_reset_chat` | Reset a chat. |
31
- | `POST /api_files_get` | Retrieve files. |
32
-
33
- External API calls use the `X-API-KEY` header.
34
-
35
- > [!TIP]
36
- > For exact request and response details, check the current source or the
37
- > matching DeepWiki page. That keeps the API reference tied to the code that is
38
- > actually running.
39
-
40
- ## MCP And A2A
41
-
42
- Use MCP when you want Agent Zero to call tools from another app or service.
43
-
44
- Use A2A when you want another agent to talk to Agent Zero as a collaborator.
45
-
46
- Both use the same Agent Zero instance and can be project-aware when configured
47
- that way.
48
-
49
- ## Related
50
-
51
- - [A0 CLI Connector](../guides/a0-cli-connector.md)
52
- - [MCP Setup](../guides/mcp-setup.md)
53
- - [A2A Setup](../guides/a2a-setup.md)
54
- - [API Integration](../guides/api-integration.md)
55
- - [DeepWiki for Agent Zero](https://deepwiki.com/agent0ai/agent-zero)
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:c0b8be750e59d57424cf3077ea07d71020f7c1e727eb72d58e203f51d5def254
3
+ size 1968
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
docs/developer/contributing-skills.md CHANGED
@@ -1,395 +1,3 @@
1
- # Contributing Skills to Agent Zero
2
-
3
- Welcome to the Agent Zero Skills ecosystem! This guide will help you create, test, and share skills with the community.
4
-
5
- ---
6
-
7
- ## What is a Skill?
8
-
9
- A **Skill** is a contextual expertise module that provides the AI agent with specialized knowledge and procedures for specific tasks. Unlike tools (which are always loaded), skills are **surfaced via description/tag matching** when relevant, making them token-efficient and context-aware.
10
-
11
- ### Skills vs Tools vs Knowledge
12
-
13
- | Aspect | Skills | Tools | Knowledge |
14
- |--------|--------|-------|-----------|
15
- | **Loading** | Description/tag matching | Always in prompt | Semantic recall |
16
- | **Purpose** | Procedures & expertise | Actions & functions | Facts & data |
17
- | **Format** | SKILL.md (YAML + Markdown) | Python/code | Text/documents |
18
- | **When to use** | "How to do X" | "Do X now" | "What is X" |
19
-
20
- ### Cross-Platform Compatibility
21
-
22
- The SKILL.md standard is compatible with:
23
- - **Agent Zero** (this project)
24
- - **Claude Code** (Anthropic)
25
- - **Cursor** (AI IDE)
26
- - **OpenAI Codex CLI**
27
- - **GitHub Copilot**
28
- - **Goose** (Block)
29
-
30
- Skills you create here can be used in any of these platforms!
31
-
32
- ---
33
-
34
- ## Quick Start
35
-
36
- ### Using the CLI (Recommended)
37
-
38
- ```bash
39
- # Create a new skill interactively
40
- python -m helpers.skills_cli create my-skill-name
41
-
42
- # List all available skills
43
- python -m helpers.skills_cli list
44
-
45
- # Validate a skill
46
- python -m helpers.skills_cli validate my-skill-name
47
-
48
- # Search skills
49
- python -m helpers.skills_cli search "keyword"
50
- ```
51
-
52
- ### Manual Creation
53
-
54
- 1. Create a folder in `usr/skills/` with your skill name
55
- 2. Add a `SKILL.md` file with YAML frontmatter
56
- 3. Optionally add supporting scripts (`.py`, `.sh`, `.js`)
57
-
58
- ---
59
-
60
- ## SKILL.md Standard
61
-
62
- Every skill must have a `SKILL.md` file with this structure:
63
-
64
- ```markdown
65
- ---
66
- name: "skill-name"
67
- description: "A clear, concise description of what this skill does and when to use it"
68
- version: "1.0.0"
69
- author: "Your Name <email@example.com>"
70
- license: "MIT"
71
- tags: ["category", "purpose", "technology"]
72
- triggers:
73
- - "keyword that activates this skill"
74
- - "another trigger phrase"
75
- allowed_tools:
76
- - tool_name
77
- - another_tool
78
- metadata:
79
- complexity: "beginner|intermediate|advanced"
80
- category: "development|devops|data|productivity|creative"
81
- estimated_time: "5 minutes"
82
- ---
83
-
84
- # Skill Name
85
-
86
- ## Overview
87
-
88
- Brief description of what this skill accomplishes.
89
-
90
- ## When to Use
91
-
92
- - Situation 1 where this skill applies
93
- - Situation 2 where this skill applies
94
-
95
- ## Instructions
96
-
97
- ### Step 1: First Step
98
-
99
- Detailed instructions...
100
-
101
- ### Step 2: Second Step
102
-
103
- More instructions...
104
-
105
- ## Examples
106
-
107
- ### Example 1: Basic Usage
108
-
109
- \`\`\`python
110
- # Code example
111
- \`\`\`
112
-
113
- ### Example 2: Advanced Usage
114
-
115
- \`\`\`python
116
- # Advanced code example
117
- \`\`\`
118
-
119
- ## Common Pitfalls
120
-
121
- - Pitfall 1 and how to avoid it
122
- - Pitfall 2 and how to avoid it
123
-
124
- ## Related Skills
125
-
126
- - `related-skill-1`
127
- - `related-skill-2`
128
- ```
129
-
130
- ### Required Fields
131
-
132
- | Field | Description |
133
- |-------|-------------|
134
- | `name` | Unique identifier (lowercase, hyphens allowed) |
135
- | `description` | What the skill does (used for semantic matching) |
136
-
137
- ### Optional Fields
138
-
139
- | Field | Description |
140
- |-------|-------------|
141
- | `version` | Semantic version (e.g., "1.0.0") |
142
- | `author` | Your name and email |
143
- | `license` | License (MIT, Apache-2.0, etc.) |
144
- | `tags` | Categories for discovery |
145
- | `triggers` | Phrases that activate this skill |
146
- | `allowed_tools` | Tools this skill can use |
147
- | `metadata` | Additional structured data |
148
-
149
- ---
150
-
151
- ## Creating Your First Skill
152
-
153
- ### Step 1: Identify the Need
154
-
155
- Ask yourself:
156
- - What expertise would help the agent?
157
- - When should this skill be activated?
158
- - What steps should the agent follow?
159
-
160
- ### Step 2: Create the Structure
161
-
162
- ```bash
163
- # Using CLI
164
- python -m helpers.skills_cli create my-awesome-skill
165
-
166
- # Or manually
167
- mkdir -p usr/skills/my-awesome-skill
168
- touch usr/skills/my-awesome-skill/SKILL.md
169
- ```
170
-
171
- ### Step 3: Write the SKILL.md
172
-
173
- ```markdown
174
- ---
175
- name: "my-awesome-skill"
176
- description: "Helps with [specific task] when [specific situation]"
177
- version: "1.0.0"
178
- author: "Your Name"
179
- tags: ["category"]
180
- ---
181
-
182
- # My Awesome Skill
183
-
184
- ## When to Use
185
-
186
- Use this skill when you need to [specific task].
187
-
188
- ## Instructions
189
-
190
- 1. First, do this...
191
- 2. Then, do that...
192
- 3. Finally, verify by...
193
-
194
- ## Examples
195
-
196
- ### Example: Basic Case
197
-
198
- [Show a complete example]
199
- ```
200
-
201
- ### Step 4: Add Supporting Files (Optional)
202
-
203
- If your skill needs scripts:
204
-
205
- ```
206
- my-awesome-skill/
207
- ├── SKILL.md # Required
208
- ├── helper.py # Optional Python script
209
- ├── setup.sh # Optional shell script
210
- └── templates/ # Optional templates folder
211
- └── config.json
212
- ```
213
-
214
- Reference them in your SKILL.md:
215
-
216
- ```markdown
217
- ## Scripts
218
-
219
- This skill includes helper scripts:
220
- - `helper.py` - Does X
221
- - `setup.sh` - Sets up Y
222
- ```
223
-
224
- ### Step 5: Test Your Skill
225
-
226
- ```bash
227
- # Validate the skill
228
- python -m helpers.skills_cli validate my-awesome-skill
229
-
230
- # Test in Agent Zero
231
- # Start the agent and ask it to perform the task your skill handles
232
- ```
233
-
234
- ---
235
-
236
- ## Best Practices
237
-
238
- ### Writing Effective Descriptions
239
-
240
- The `description` field is crucial for semantic matching. Make it:
241
-
242
- **Good:**
243
- ```yaml
244
- description: "Guides systematic debugging of Python applications using print statements, debugger, and logging to identify root causes"
245
- ```
246
-
247
- **Bad:**
248
- ```yaml
249
- description: "Helps with debugging"
250
- ```
251
-
252
- ### Structuring Instructions
253
-
254
- 1. **Be Specific** - Avoid vague instructions
255
- 2. **Use Steps** - Number your steps clearly
256
- 3. **Include Examples** - Show, don't just tell
257
- 4. **Anticipate Errors** - Include troubleshooting
258
-
259
- ### Semantic Triggers
260
-
261
- Design your description and content so the skill is recalled when relevant:
262
-
263
- ```yaml
264
- # Include synonyms and related terms
265
- description: "Helps create REST APIs, web services, HTTP endpoints, and backend routes using FastAPI, Flask, or Express"
266
- ```
267
-
268
- ### Keep Skills Focused
269
-
270
- One skill = one expertise area. If your skill is getting too long, split it:
271
-
272
- - `api-design` - API structure and patterns
273
- - `api-security` - API authentication and authorization
274
- - `api-testing` - API testing strategies
275
-
276
- ---
277
-
278
- ## Testing Skills
279
-
280
- ### Local Testing
281
-
282
- 1. **Validate Structure:**
283
- ```bash
284
- python -m helpers.skills_cli validate my-skill
285
- ```
286
-
287
- 2. **Test Semantic Recall:**
288
- Start Agent Zero and ask questions that should trigger your skill.
289
-
290
- 3. **Verify Instructions:**
291
- Follow your own instructions manually to ensure they work.
292
-
293
- ---
294
-
295
- ## Sharing Skills
296
-
297
- ### Contributing to Agent Zero
298
-
299
- 1. **Fork the Repository:**
300
- ```bash
301
- git clone https://github.com/agent0ai/agent-zero.git
302
- cd agent-zero
303
- ```
304
-
305
- 2. **Create Your Skill:**
306
- ```bash
307
- python -m helpers.skills_cli create my-skill
308
- # Edit usr/skills/my-skill/SKILL.md
309
- ```
310
-
311
- 3. **Move to Default (for contribution):**
312
- ```bash
313
- mv usr/skills/my-skill skills/my-skill
314
- ```
315
-
316
- 4. **Create a Pull Request:**
317
- - Branch: `feat/skill-my-skill-name`
318
- - Title: `feat(skills): add my-skill-name skill`
319
- - Description: Explain what the skill does and why it's useful
320
-
321
- ### Publishing Skills
322
-
323
- Share your skills on [skillsmp.com](https://skillsmp.com) or [skills.sh](https://skills.sh):
324
-
325
- 1. Create a GitHub repository for your skill
326
- 2. Ensure it follows the SKILL.md standard
327
- 3. Submit via their contribution process
328
-
329
- ### Creating a Skills Collection
330
-
331
- For multiple related skills, create a repository:
332
-
333
- ```
334
- my-skills-collection/
335
- ├── README.md
336
- ├── skills/
337
- │ ├── skill-1/
338
- │ │ └── SKILL.md
339
- │ ├── skill-2/
340
- │ │ └── SKILL.md
341
- │ └── skill-3/
342
- │ └── SKILL.md
343
- └── LICENSE
344
- ```
345
-
346
- ---
347
-
348
- ## Community Guidelines
349
-
350
- ### Quality Standards
351
-
352
- - **Tested** - Skills must be tested before submission
353
- - **Documented** - Clear instructions and examples
354
- - **Focused** - One expertise per skill
355
- - **Original** - Don't duplicate existing skills
356
-
357
- ### Naming Conventions
358
-
359
- - Use lowercase with hyphens: `my-skill-name`
360
- - Be descriptive: `python-debugging` not `debug`
361
- - Avoid generic names: `fastapi-crud` not `api`
362
-
363
- ### License
364
-
365
- - Include a license (MIT recommended for maximum compatibility)
366
- - Respect licenses of any code you include
367
- - Don't include proprietary or copyrighted content
368
-
369
- ---
370
-
371
- ## FAQ
372
-
373
- ### Q: Where should I put my skills?
374
-
375
- **A:** During development, use `usr/skills/`. For contribution, move to `skills/`.
376
-
377
- ### Q: How are skills discovered?
378
-
379
- **A:** Skills are matched against their name, description, and tags for the current query. They are not indexed into vector memory.
380
-
381
- ### Q: Can I use skills from other platforms?
382
-
383
- **A:** Yes! The SKILL.md standard is cross-platform. Skills from Claude Code, Cursor, or other compatible platforms can be copied directly to `usr/skills/`.
384
-
385
- ### Q: How do I update a skill?
386
-
387
- **A:** Edit the SKILL.md file and increment the version number. Changes take effect on agent restart.
388
-
389
- ### Q: Can skills call other skills?
390
-
391
- **A:** Skills don't directly call each other, but the agent may combine multiple skills when appropriate for a task.
392
-
393
- ---
394
-
395
- Happy skill building! 🚀
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:50705bc9123c5c9962e9a0582b466c5bdfa342770f832503fe58cb77b51f4fa8
3
+ size 9033
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
docs/developer/extensions.md CHANGED
@@ -1,46 +1,3 @@
1
- # Extensions
2
-
3
- Extensions are an advanced way to change how Agent Zero behaves.
4
-
5
- If you are new, start with plugins instead. Plugins are easier to create, test,
6
- disable, and remove.
7
-
8
- Architecture details, extension points, and source-linked explanations now live
9
- in [DeepWiki for Agent Zero](https://deepwiki.com/agent0ai/agent-zero). This
10
- local page stays short on purpose.
11
-
12
- ## Start Here
13
-
14
- | Goal | Start here |
15
- | --- | --- |
16
- | Add a small user-facing feature | [Create a Small Plugin](../guides/create-plugin.md) |
17
- | Change agent behavior for a project | [Projects](../guides/projects.md) |
18
- | Create a specialized agent style | [Agent Profiles](../guides/agent-profiles.md) |
19
- | Study extension internals | [DeepWiki](https://deepwiki.com/agent0ai/agent-zero) |
20
-
21
- ## When Extensions Make Sense
22
-
23
- Use an extension only when a normal plugin, project instruction, skill, or agent
24
- profile is not enough.
25
-
26
- Good extension candidates:
27
-
28
- - adding behavior at a specific lifecycle point;
29
- - shaping prompts in a reusable way;
30
- - integrating tightly with core tools;
31
- - preparing framework-owned state before a task starts.
32
-
33
- Avoid extensions for simple UI changes, one-off scripts, or work that should be
34
- easy to remove. A plugin is usually the cleaner home for that.
35
-
36
- ## Maintenance Rule
37
-
38
- Keep extension changes small and easy to explain. If a reader needs the full
39
- architecture to understand why the extension exists, link to the relevant
40
- DeepWiki page instead of copying the architecture into this repository.
41
-
42
- ## Related
43
-
44
- - [Create a Small Plugin](../guides/create-plugin.md)
45
- - [Agent Profiles](../guides/agent-profiles.md)
46
- - [DeepWiki for Agent Zero](https://deepwiki.com/agent0ai/agent-zero)
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:bb77856495cd10198eca601ba2ea1cfd4043470d966522462d9589fc9a908aff
3
+ size 1682
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
docs/developer/mcp-configuration.md CHANGED
@@ -1,80 +1,3 @@
1
- # Advanced MCP Configuration
2
-
3
- Most users should start with [MCP Setup](../guides/mcp-setup.md).
4
-
5
- This page is for people who need to paste or review MCP JSON by hand. MCP
6
- architecture and source-linked internals live in
7
- [DeepWiki for Agent Zero](https://deepwiki.com/agent0ai/agent-zero).
8
-
9
- ## Basic Shape
10
-
11
- Command-based MCP tool:
12
-
13
- ```json
14
- {
15
- "mcpServers": {
16
- "sqlite": {
17
- "command": "uvx",
18
- "args": ["mcp-server-sqlite", "--db-path", "/root/db.sqlite"]
19
- }
20
- }
21
- }
22
- ```
23
-
24
- URL-based MCP tool:
25
-
26
- ```json
27
- {
28
- "mcpServers": {
29
- "external-api": {
30
- "url": "https://api.example.com/mcp",
31
- "headers": {
32
- "Authorization": "Bearer YOUR_API_KEY"
33
- }
34
- }
35
- }
36
- }
37
- ```
38
-
39
- ## Common Fields
40
-
41
- | Field | Meaning |
42
- | --- | --- |
43
- | `command` | Starts a local MCP tool from a command. |
44
- | `args` | Arguments passed to that command. |
45
- | `url` | Connects to an MCP tool that is already running. |
46
- | `headers` | Optional HTTP headers, often used for authentication. |
47
- | `env` | Optional environment variables for command-based tools. |
48
- | `disabled` | Temporarily turns one MCP entry off. |
49
-
50
- Use `command` for local tools and `url` for tools that are already running
51
- somewhere else.
52
-
53
- ## Docker Addresses
54
-
55
- If Agent Zero runs in Docker, remember that "localhost" means the container, not
56
- always your host machine.
57
-
58
- | Where the MCP tool runs | Address to use from Agent Zero |
59
- | --- | --- |
60
- | Host machine on macOS or Windows | `host.docker.internal` |
61
- | Another container | The container name on the same Docker network |
62
- | Remote machine | Its reachable HTTPS URL |
63
- | Inside Agent Zero's container | A command-based config |
64
-
65
- On Linux, `host.docker.internal` may need extra Docker setup. Running the MCP
66
- tool in the same Docker network is often simpler.
67
-
68
- ## Safety
69
-
70
- - Use MCP tools you trust.
71
- - Keep real API keys out of public screenshots and repositories.
72
- - Prefer project secrets or environment variables for credentials.
73
- - Remove MCP tools you no longer use.
74
-
75
- ## Related
76
-
77
- - [MCP Setup](../guides/mcp-setup.md)
78
- - [Browser Guide](../guides/browser.md)
79
- - [A0 CLI Connector](../guides/a0-cli-connector.md)
80
- - [DeepWiki for Agent Zero](https://deepwiki.com/agent0ai/agent-zero)
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:d6f96af40a0fc64e275bdc8878d9a2b75d98d819c8301d79c8f1624528b4ec22
3
+ size 2182
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
docs/developer/notifications.md CHANGED
@@ -1,133 +1,3 @@
1
- # Agent Zero Notifications
2
-
3
- Quick guide for using the notification system in Agent Zero.
4
-
5
- > [!TIP]
6
- > Notifications pair well with scheduled tasks. See [Tasks & Scheduling](../guides/usage.md#tasks-and-scheduling) for automation patterns.
7
-
8
- ## Backend Usage
9
-
10
- Use `AgentNotification` helper methods anywhere in your Python code:
11
-
12
- ```python
13
- from helpers.notification import AgentNotification
14
-
15
- # Basic notifications
16
- AgentNotification.info("Operation completed")
17
- AgentNotification.success("File saved successfully", "File Manager")
18
- AgentNotification.warning("High CPU usage detected", "System Monitor")
19
- AgentNotification.error("Connection failed", "Network Error")
20
- AgentNotification.progress("Processing files...", "Task Progress")
21
-
22
- # With details and custom display time
23
- AgentNotification.info(
24
- message="System backup completed",
25
- title="Backup Manager",
26
- detail="<p>Backup size: <strong>2.4 GB</strong></p>",
27
- display_time=8 # seconds
28
- )
29
-
30
- # Grouped notifications (replaces previous in same group)
31
- AgentNotification.progress("Download: 25%", "File Download", group="download-status")
32
- AgentNotification.progress("Download: 75%", "File Download", group="download-status") # Replaces previous
33
- AgentNotification.progress("Download: Complete!", "File Download", group="download-status") # Replaces previous
34
- ```
35
-
36
- ## Frontend Usage
37
-
38
- Use the notification store in Alpine.js components:
39
-
40
- ```javascript
41
- // Basic notifications
42
- $store.notificationStore.info("User logged in")
43
- $store.notificationStore.success("Settings saved", "Configuration")
44
- $store.notificationStore.warning("Session expiring soon")
45
- $store.notificationStore.error("Failed to load data")
46
-
47
- // With grouping
48
- $store.notificationStore.info("Connecting...", "Status", "", 3, "connection")
49
- $store.notificationStore.success("Connected!", "Status", "", 3, "connection") // Replaces previous
50
-
51
- // Frontend notifications with backend persistence (new feature!)
52
- $store.notificationStore.frontendError("Database timeout", "Connection Error")
53
- $store.notificationStore.frontendWarning("High memory usage", "Performance")
54
- $store.notificationStore.frontendInfo("Cache cleared", "System")
55
- ```
56
-
57
- ## Frontend Notifications with Backend Sync
58
-
59
- **New Feature**: Frontend notifications now automatically sync to the backend when connected, providing persistent history and cross-session availability.
60
-
61
- ### How it Works:
62
- - **Backend Connected**: Notifications are sent to backend and appear via polling (persistent)
63
- - **Backend Disconnected**: Notifications show as frontend-only toasts (temporary)
64
- - **Automatic Fallback**: Seamless degradation when backend is unavailable
65
-
66
- ### Global Functions:
67
- ```javascript
68
- // These functions automatically try backend first, then fallback to frontend-only
69
- toastFrontendError("Server unreachable", "Connection Error")
70
- toastFrontendWarning("Slow connection detected")
71
- toastFrontendInfo("Reconnected successfully")
72
- ```
73
-
74
- ## HTML Usage
75
-
76
- ```html
77
- <button @click="$store.notificationStore.success('Task completed!')">
78
- Complete Task
79
- </button>
80
-
81
- <button @click="$store.notificationStore.warning('Progress: 50%', 'Upload', '', 5, 'upload-progress')">
82
- Update Progress
83
- </button>
84
-
85
- <!-- Frontend notifications with backend sync -->
86
- <button @click="$store.notificationStore.frontendError('Connection failed', 'Network')">
87
- Report Connection Error
88
- </button>
89
- ```
90
-
91
- ## Notification Groups
92
-
93
- Groups ensure only the latest notification from each group is shown in the toast stack:
94
-
95
- ```python
96
- # Progress updates - each new notification replaces the previous one
97
- AgentNotification.info("Starting backup...", group="backup-status")
98
- AgentNotification.progress("Backup: 30%", group="backup-status") # Replaces previous
99
- AgentNotification.progress("Backup: 80%", group="backup-status") # Replaces previous
100
- AgentNotification.success("Backup complete!", group="backup-status") # Replaces previous
101
-
102
- # Connection status - only show current state
103
- AgentNotification.warning("Disconnected", group="network")
104
- AgentNotification.info("Reconnecting...", group="network") # Replaces previous
105
- AgentNotification.success("Connected", group="network") # Replaces previous
106
- ```
107
-
108
- ## Parameters
109
-
110
- All notification methods support these parameters:
111
-
112
- - `message` (required): Main notification text
113
- - `title` (optional): Notification title
114
- - `detail` (optional): HTML content for expandable details
115
- - `display_time` (optional): Toast display duration in seconds (default: 3)
116
- - `group` (optional): Group identifier for replacement behavior
117
-
118
- ## Types
119
-
120
- - **info** (ℹ️): General information
121
- - **success** (✅): Successful operations
122
- - **warning** (⚠️): Important alerts
123
- - **error** (❌): Error conditions
124
- - **progress** (⏳): Ongoing operations
125
-
126
- ## Behavior
127
-
128
- - **Toast Display**: Notifications appear as toasts in the bottom-right corner
129
- - **Persistent History**: All notifications (including synced frontend ones) are stored in notification history
130
- - **Modal Access**: Full history accessible via the bell icon
131
- - **Auto-dismiss**: Toasts automatically disappear after `display_time`
132
- - **Group Replacement**: Notifications with the same group replace previous ones immediately
133
- - **Backend Sync**: Frontend notifications automatically sync to backend when connected
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:f9cececccc005a4c071574c5706cb157e744f60cbba1e0cceaa442936caf78fc
3
+ size 5212