@turmind/halo 0.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +143 -0
- package/admin-out/404.html +1 -0
- package/admin-out/_next/static/IBP_mwBDf-cPwZSZZGpi8/_buildManifest.js +1 -0
- package/admin-out/_next/static/IBP_mwBDf-cPwZSZZGpi8/_ssgManifest.js +1 -0
- package/admin-out/_next/static/chunks/1d2d5650-810a3ca1ae20cab5.js +18 -0
- package/admin-out/_next/static/chunks/200.3b8f8a74f005a134.js +1 -0
- package/admin-out/_next/static/chunks/220.3dc41cd6269b88e6.js +1 -0
- package/admin-out/_next/static/chunks/298-d6b224b569da4de0.js +1 -0
- package/admin-out/_next/static/chunks/304eda7d.b1ee7f523653e027.js +1 -0
- package/admin-out/_next/static/chunks/330.3b784cf0dcd69163.js +1 -0
- package/admin-out/_next/static/chunks/442.f4302087bddb1ec1.js +1 -0
- package/admin-out/_next/static/chunks/443.d1b289781793f8de.js +25 -0
- package/admin-out/_next/static/chunks/503-7c6d9935df6e0cea.js +1 -0
- package/admin-out/_next/static/chunks/533.5f2d4bfe3d076095.js +1 -0
- package/admin-out/_next/static/chunks/579.a2718ddd395a2f3a.js +1 -0
- package/admin-out/_next/static/chunks/635-3dd0043ed0520b9d.js +1 -0
- package/admin-out/_next/static/chunks/65.859665ba6717967a.js +1 -0
- package/admin-out/_next/static/chunks/661.a4fe93f3f2a5e871.js +1 -0
- package/admin-out/_next/static/chunks/688.4e014ac6cfc7e152.js +1 -0
- package/admin-out/_next/static/chunks/868.0c95dfe283400a00.js +1 -0
- package/admin-out/_next/static/chunks/app/_not-found/page-8e35399c8fd5016d.js +1 -0
- package/admin-out/_next/static/chunks/app/layout-58f773336e6fce61.js +1 -0
- package/admin-out/_next/static/chunks/app/page-cc8043335282d745.js +1 -0
- package/admin-out/_next/static/chunks/db534642.09d3c650ff587175.js +1 -0
- package/admin-out/_next/static/chunks/fb4ec4d6-3fa44f69484f91b9.js +1 -0
- package/admin-out/_next/static/chunks/framework-c3031ae54a63fe16.js +1 -0
- package/admin-out/_next/static/chunks/main-14b48e3c2588354f.js +1 -0
- package/admin-out/_next/static/chunks/main-app-483b436873410ddc.js +1 -0
- package/admin-out/_next/static/chunks/pages/_app-b2fc6e5f920d1b1a.js +1 -0
- package/admin-out/_next/static/chunks/pages/_error-f3696a8f3d67d150.js +1 -0
- package/admin-out/_next/static/chunks/polyfills-42372ed130431b0a.js +1 -0
- package/admin-out/_next/static/chunks/webpack-8bd7ef88a6527feb.js +1 -0
- package/admin-out/_next/static/css/659eccb5db697b76.css +1 -0
- package/admin-out/_next/static/css/8fce4e1a54dac12a.css +3 -0
- package/admin-out/_next/static/media/19cfc7226ec3afaa-s.woff2 +0 -0
- package/admin-out/_next/static/media/21350d82a1f187e9-s.woff2 +0 -0
- package/admin-out/_next/static/media/8e9860b6e62d6359-s.woff2 +0 -0
- package/admin-out/_next/static/media/ba9851c3c22cd980-s.woff2 +0 -0
- package/admin-out/_next/static/media/c5fe6dc8356a8c31-s.woff2 +0 -0
- package/admin-out/_next/static/media/df0a9ae256c0569c-s.woff2 +0 -0
- package/admin-out/_next/static/media/e4af272ccee01ff0-s.p.woff2 +0 -0
- package/admin-out/favicon.ico +0 -0
- package/admin-out/icon.svg +18 -0
- package/admin-out/index.html +1 -0
- package/admin-out/index.txt +23 -0
- package/admin-out/monaco/vs/_commonjsHelpers-CT9FvmAN.js +1 -0
- package/admin-out/monaco/vs/abap-D-t0cyap.js +1 -0
- package/admin-out/monaco/vs/apex-CcIm7xu6.js +1 -0
- package/admin-out/monaco/vs/assets/css.worker-HnVq6Ewq.js +93 -0
- package/admin-out/monaco/vs/assets/editor.worker-Be8ye1pW.js +26 -0
- package/admin-out/monaco/vs/assets/html.worker-B51mlPHg.js +470 -0
- package/admin-out/monaco/vs/assets/json.worker-DKiEKt88.js +58 -0
- package/admin-out/monaco/vs/assets/ts.worker-CMbG-7ft.js +67731 -0
- package/admin-out/monaco/vs/azcli-BA0tQDCg.js +1 -0
- package/admin-out/monaco/vs/basic-languages/monaco.contribution.js +1 -0
- package/admin-out/monaco/vs/bat-C397hTD6.js +1 -0
- package/admin-out/monaco/vs/bicep-DF5aW17k.js +2 -0
- package/admin-out/monaco/vs/cameligo-plsz8qhj.js +1 -0
- package/admin-out/monaco/vs/clojure-Y2auQMzK.js +1 -0
- package/admin-out/monaco/vs/coffee-Bu45yuWE.js +1 -0
- package/admin-out/monaco/vs/cpp-CkKPQIni.js +1 -0
- package/admin-out/monaco/vs/csharp-CX28MZyh.js +1 -0
- package/admin-out/monaco/vs/csp-D8uWnyxW.js +1 -0
- package/admin-out/monaco/vs/css-CaeNmE3S.js +3 -0
- package/admin-out/monaco/vs/cssMode-CjiAH6dQ.js +1 -0
- package/admin-out/monaco/vs/cypher-DVThT8BS.js +1 -0
- package/admin-out/monaco/vs/dart-CmGfCvrO.js +1 -0
- package/admin-out/monaco/vs/dockerfile-CZqqYdch.js +1 -0
- package/admin-out/monaco/vs/ecl-30fUercY.js +1 -0
- package/admin-out/monaco/vs/editor/editor.main.css +1 -0
- package/admin-out/monaco/vs/editor/editor.main.js +5 -0
- package/admin-out/monaco/vs/editor.api-CalNCsUg.js +903 -0
- package/admin-out/monaco/vs/elixir-xjPaIfzF.js +1 -0
- package/admin-out/monaco/vs/flow9-DqtmStfK.js +1 -0
- package/admin-out/monaco/vs/freemarker2-Cz_sV6Md.js +3 -0
- package/admin-out/monaco/vs/fsharp-BOMdg4U1.js +1 -0
- package/admin-out/monaco/vs/go-D_hbi-Jt.js +1 -0
- package/admin-out/monaco/vs/graphql-CKUU4kLG.js +1 -0
- package/admin-out/monaco/vs/handlebars-OwglfO-1.js +1 -0
- package/admin-out/monaco/vs/hcl-DTaboeZW.js +1 -0
- package/admin-out/monaco/vs/html-Pa1xEWsY.js +1 -0
- package/admin-out/monaco/vs/htmlMode-Bz67EXwp.js +1 -0
- package/admin-out/monaco/vs/ini-CsNwO04R.js +1 -0
- package/admin-out/monaco/vs/java-CI4ZMsH9.js +1 -0
- package/admin-out/monaco/vs/javascript-PczUCGdz.js +1 -0
- package/admin-out/monaco/vs/jsonMode-DULH5oaX.js +7 -0
- package/admin-out/monaco/vs/julia-BwzEvaQw.js +1 -0
- package/admin-out/monaco/vs/kotlin-IUYPiTV8.js +1 -0
- package/admin-out/monaco/vs/language/css/monaco.contribution.js +1 -0
- package/admin-out/monaco/vs/language/html/monaco.contribution.js +1 -0
- package/admin-out/monaco/vs/language/json/monaco.contribution.js +1 -0
- package/admin-out/monaco/vs/language/typescript/monaco.contribution.js +1 -0
- package/admin-out/monaco/vs/less-C0eDYdqa.js +2 -0
- package/admin-out/monaco/vs/lexon-iON-Kj97.js +1 -0
- package/admin-out/monaco/vs/liquid-DqKjdPGy.js +1 -0
- package/admin-out/monaco/vs/loader.js +1368 -0
- package/admin-out/monaco/vs/lspLanguageFeatures-kM9O9rjY.js +4 -0
- package/admin-out/monaco/vs/lua-DtygF91M.js +1 -0
- package/admin-out/monaco/vs/m3-CsR4AuFi.js +1 -0
- package/admin-out/monaco/vs/markdown-C_rD0bIw.js +1 -0
- package/admin-out/monaco/vs/mdx-DEWtB1K5.js +1 -0
- package/admin-out/monaco/vs/mips-CiYP61RB.js +1 -0
- package/admin-out/monaco/vs/monaco.contribution-D2OdxNBt.js +1 -0
- package/admin-out/monaco/vs/monaco.contribution-DO3azKX8.js +1 -0
- package/admin-out/monaco/vs/monaco.contribution-EcChJV6a.js +1 -0
- package/admin-out/monaco/vs/monaco.contribution-qLAYrEOP.js +1 -0
- package/admin-out/monaco/vs/msdax-C38-sJlp.js +1 -0
- package/admin-out/monaco/vs/mysql-CdtbpvbG.js +1 -0
- package/admin-out/monaco/vs/nls.messages-loader.js +1 -0
- package/admin-out/monaco/vs/nls.messages.cs.js.js +17 -0
- package/admin-out/monaco/vs/nls.messages.de.js.js +17 -0
- package/admin-out/monaco/vs/nls.messages.es.js.js +17 -0
- package/admin-out/monaco/vs/nls.messages.fr.js.js +15 -0
- package/admin-out/monaco/vs/nls.messages.it.js.js +15 -0
- package/admin-out/monaco/vs/nls.messages.ja.js.js +17 -0
- package/admin-out/monaco/vs/nls.messages.js.js +10 -0
- package/admin-out/monaco/vs/nls.messages.ko.js.js +25 -0
- package/admin-out/monaco/vs/nls.messages.pl.js.js +17 -0
- package/admin-out/monaco/vs/nls.messages.pt-br.js.js +6 -0
- package/admin-out/monaco/vs/nls.messages.ru.js.js +17 -0
- package/admin-out/monaco/vs/nls.messages.tr.js.js +15 -0
- package/admin-out/monaco/vs/nls.messages.zh-cn.js.js +17 -0
- package/admin-out/monaco/vs/nls.messages.zh-tw.js.js +15 -0
- package/admin-out/monaco/vs/objective-c-CntZFaHX.js +1 -0
- package/admin-out/monaco/vs/pascal-r6kuqfl_.js +1 -0
- package/admin-out/monaco/vs/pascaligo-BiXoTmXh.js +1 -0
- package/admin-out/monaco/vs/perl-DABw_TcH.js +1 -0
- package/admin-out/monaco/vs/pgsql-me_jFXeX.js +1 -0
- package/admin-out/monaco/vs/php-D_kh-9LK.js +1 -0
- package/admin-out/monaco/vs/pla-VfZjczW0.js +1 -0
- package/admin-out/monaco/vs/postiats-BBSzz8Pk.js +1 -0
- package/admin-out/monaco/vs/powerquery-Dt-g_2cc.js +1 -0
- package/admin-out/monaco/vs/powershell-B-7ap1zc.js +1 -0
- package/admin-out/monaco/vs/protobuf-BmtuEB1A.js +2 -0
- package/admin-out/monaco/vs/pug-BRpRNeEb.js +1 -0
- package/admin-out/monaco/vs/python-Cr0UkIbn.js +1 -0
- package/admin-out/monaco/vs/qsharp-BzsFaUU9.js +1 -0
- package/admin-out/monaco/vs/r-f8dDdrp4.js +1 -0
- package/admin-out/monaco/vs/razor-BYAHOTkz.js +1 -0
- package/admin-out/monaco/vs/redis-fvZQY4PI.js +1 -0
- package/admin-out/monaco/vs/redshift-45Et0LQi.js +1 -0
- package/admin-out/monaco/vs/restructuredtext-C7UUFKFD.js +1 -0
- package/admin-out/monaco/vs/ruby-CZO8zYTz.js +1 -0
- package/admin-out/monaco/vs/rust-Bfetafyc.js +1 -0
- package/admin-out/monaco/vs/sb-3GYllVck.js +1 -0
- package/admin-out/monaco/vs/scala-foMgrKo1.js +1 -0
- package/admin-out/monaco/vs/scheme-CHdMtr7p.js +1 -0
- package/admin-out/monaco/vs/scss-C1cmLt9V.js +3 -0
- package/admin-out/monaco/vs/shell-ClXCKCEW.js +1 -0
- package/admin-out/monaco/vs/solidity-MZ6ExpPy.js +1 -0
- package/admin-out/monaco/vs/sophia-DWkuSsPQ.js +1 -0
- package/admin-out/monaco/vs/sparql-AUGFYSyk.js +1 -0
- package/admin-out/monaco/vs/sql-32GpJSV2.js +1 -0
- package/admin-out/monaco/vs/st-CuDFIVZ_.js +1 -0
- package/admin-out/monaco/vs/swift-n-2HociN.js +3 -0
- package/admin-out/monaco/vs/systemverilog-Ch4vA8Yt.js +1 -0
- package/admin-out/monaco/vs/tcl-D74tq1nH.js +1 -0
- package/admin-out/monaco/vs/tsMode-CZz1Umrk.js +11 -0
- package/admin-out/monaco/vs/twig-C6taOxMV.js +1 -0
- package/admin-out/monaco/vs/typescript-DfOrAzoV.js +1 -0
- package/admin-out/monaco/vs/typespec-D-PIh9Xw.js +1 -0
- package/admin-out/monaco/vs/vb-Dyb2648j.js +1 -0
- package/admin-out/monaco/vs/wgsl-BhLXMOR0.js +298 -0
- package/admin-out/monaco/vs/workers-DcJshg-q.js +1 -0
- package/admin-out/monaco/vs/xml-CdsdnY8S.js +1 -0
- package/admin-out/monaco/vs/yaml-DYGvmE88.js +1 -0
- package/bin/halo.js +9 -0
- package/bundled-docs/design/agent.md +145 -0
- package/bundled-docs/design/architecture.md +270 -0
- package/bundled-docs/design/background-dispatch.md +151 -0
- package/bundled-docs/design/command.md +58 -0
- package/bundled-docs/design/cron.md +88 -0
- package/bundled-docs/design/evolution.md +383 -0
- package/bundled-docs/design/express-self.md +145 -0
- package/bundled-docs/design/feishu.md +224 -0
- package/bundled-docs/design/halo-city.md +112 -0
- package/bundled-docs/design/prompt-system.md +411 -0
- package/bundled-docs/design/session.md +321 -0
- package/bundled-docs/design/slack.md +212 -0
- package/bundled-docs/design/storage.md +578 -0
- package/bundled-docs/design/telegram.md +161 -0
- package/bundled-docs/design/web.md +222 -0
- package/bundled-docs/design/wechat.md +146 -0
- package/bundled-docs/design/ws.md +144 -0
- package/bundled-docs/dev/acp-adapter.md +337 -0
- package/bundled-docs/dev/add-channel.md +376 -0
- package/bundled-docs/dev/add-model-provider.md +386 -0
- package/bundled-docs/dev/api.md +686 -0
- package/bundled-docs/dev/deploy.md +198 -0
- package/bundled-docs/dev/desktop-packaging.md +327 -0
- package/bundled-docs/dev/env.md +158 -0
- package/bundled-docs/dev/logging.md +85 -0
- package/bundled-docs/dev/previews.md +225 -0
- package/bundled-docs/dev/tools.md +331 -0
- package/bundled-docs/guide/README.md +29 -0
- package/bundled-docs/guide/agents.md +264 -0
- package/bundled-docs/guide/channels/README.md +62 -0
- package/bundled-docs/guide/channels/acp.md +150 -0
- package/bundled-docs/guide/channels/feishu.md +154 -0
- package/bundled-docs/guide/channels/slack.md +156 -0
- package/bundled-docs/guide/channels/telegram.md +112 -0
- package/bundled-docs/guide/channels/web.md +149 -0
- package/bundled-docs/guide/channels/wechat.md +110 -0
- package/bundled-docs/guide/chat.md +112 -0
- package/bundled-docs/guide/cli.md +197 -0
- package/bundled-docs/guide/getting-started.md +93 -0
- package/bundled-docs/guide/secrets-and-credentials.md +161 -0
- package/bundled-docs/guide/sessions.md +104 -0
- package/bundled-docs/guide/skills.md +302 -0
- package/bundled-docs/guide/testing-agents-and-skills.md +136 -0
- package/bundled-docs/guide/workspace.md +131 -0
- package/bundled-docs/plans/cron-tasks.md +362 -0
- package/bundled-docs/plans/design-suggestions.md +203 -0
- package/bundled-docs/plans/issue-session-deep-nesting.md +208 -0
- package/bundled-docs/plans/launch-plan.md +111 -0
- package/bundled-docs/plans/md-and-agent-refactor.md +197 -0
- package/bundled-docs/plans/remote-mac-worker.md +196 -0
- package/bundled-docs/plans/roadmap.md +40 -0
- package/bundled-docs/plans/self-evolution.md +1379 -0
- package/bundled-docs/plans/todo.md +32 -0
- package/bundled-docs/plans/weixin-channel.md +255 -0
- package/bundled-docs/requirements/agent.md +92 -0
- package/bundled-docs/requirements/chat.md +81 -0
- package/bundled-docs/requirements/command.md +130 -0
- package/bundled-docs/requirements/editor.md +82 -0
- package/bundled-docs/requirements/explorer.md +89 -0
- package/bundled-docs/requirements/overview.md +62 -0
- package/bundled-docs/requirements/session.md +73 -0
- package/bundled-docs/requirements/settings.md +224 -0
- package/bundled-docs/requirements/skill.md +125 -0
- package/bundled-docs/requirements/source-control.md +82 -0
- package/bundled-docs/requirements/terminal.md +118 -0
- package/bundled-docs/requirements/workspace.md +80 -0
- package/bundled-docs/test/docs-seeding.md +101 -0
- package/bundled-docs/test/session.md +374 -0
- package/dist/index.js +26750 -0
- package/package.json +67 -0
- package/templates/INSTRUCTIONS.md +25 -0
- package/templates/agents/__apply_agent__/AGENT.md +229 -0
- package/templates/agents/__apply_agent__/agent.yaml +30 -0
- package/templates/agents/__evo_agent__/AGENT.md +323 -0
- package/templates/agents/__evo_agent__/agent.yaml +29 -0
- package/templates/agents/__score__/AGENT.md +177 -0
- package/templates/agents/__score__/agent.yaml +29 -0
- package/templates/agents/deep-executor/AGENT.md +60 -0
- package/templates/agents/deep-executor/agent.yaml +25 -0
- package/templates/agents/default/AGENT.md +38 -0
- package/templates/agents/default/agent.yaml +51 -0
- package/templates/agents/executor/AGENT.md +38 -0
- package/templates/agents/executor/agent.yaml +25 -0
- package/templates/aliases.yaml +26 -0
- package/templates/canvas/self.html +660 -0
- package/templates/config.yaml +69 -0
- package/templates/models/anthropic.yaml +47 -0
- package/templates/models/aws-bedrock-claude-invoke.yaml +156 -0
- package/templates/models/aws-bedrock-mantle.yaml +89 -0
- package/templates/models/deepseek.yaml +62 -0
- package/templates/models/doubao.yaml +137 -0
- package/templates/models/hunyuan.yaml +56 -0
- package/templates/models/kimi.yaml +41 -0
- package/templates/models/mimo-token-plan-china.yaml +61 -0
- package/templates/models/minimax.yaml +80 -0
- package/templates/models/openai.yaml +51 -0
- package/templates/models/qwen.yaml +78 -0
- package/templates/optional-skills/tavily-web-search/SKILL.md +91 -0
- package/templates/optional-skills/tavily-web-search/config.yaml +10 -0
- package/templates/prompts/all/TOOL_GUIDELINES.md +35 -0
- package/templates/prompts/all/TOOL_SHELL.md +4 -0
- package/templates/prompts/all/TOOL_SHELL.windows.md +7 -0
- package/templates/prompts/bootstrap/BOOTSTRAP.md +26 -0
- package/templates/prompts/root/WORKSPACE_MEMORY.md +11 -0
- package/templates/schema.sql +30 -0
- package/templates/skills/acp/SKILL.md +236 -0
- package/templates/skills/acp/templates/SKILL.md.tmpl +74 -0
- package/templates/skills/acp/templates/ask.py +176 -0
- package/templates/skills/acp/templates/config.yaml.tmpl +33 -0
- package/templates/skills/agent/SKILL.md +128 -0
- package/templates/skills/aws-knowledge/SKILL.md +82 -0
- package/templates/skills/aws-knowledge/scripts/aws_kb.py +61 -0
- package/templates/skills/cron/SKILL.md +217 -0
- package/templates/skills/cron/manage-cron.py +434 -0
- package/templates/skills/halo/SKILL.md +98 -0
- package/templates/skills/nova-web-search/SKILL.md +65 -0
- package/templates/skills/self/SKILL.md +139 -0
- package/templates/skills/send-file/SKILL.md +28 -0
- package/templates/skills/send-file/feishu.md +16 -0
- package/templates/skills/send-file/slack.md +7 -0
- package/templates/skills/send-file/telegram.md +9 -0
- package/templates/skills/send-file/web.md +6 -0
- package/templates/skills/send-file/wechat.md +8 -0
- package/templates/skills/skill/SKILL.md +131 -0
- package/templates/skills/workspace/SKILL.md +28 -0
- package/templates/skills/workspace/setup-tidy.md +265 -0
- package/templates/skills/workspace/share.md +187 -0
- package/templates/skills/workspace/stage.py +487 -0
|
@@ -0,0 +1,578 @@
|
|
|
1
|
+
# Storage Protocol
|
|
2
|
+
|
|
3
|
+
Defines the persisted-data format for every Halo surface. Format changes must respect the compatibility rules in this doc.
|
|
4
|
+
|
|
5
|
+
## Directory layout
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
~/.halo/ # Global (user-level)
|
|
9
|
+
├── global/ # Non-sensitive config + data
|
|
10
|
+
│ ├── INSTRUCTIONS.md # Global instructions (injected into every agent)
|
|
11
|
+
│ ├── USER.md # User profile (bootstrap-generated)
|
|
12
|
+
│ ├── prompts/ # User-editable system prompts (externalised)
|
|
13
|
+
│ │ ├── bootstrap/BOOTSTRAP.md # First-run guidance
|
|
14
|
+
│ │ ├── all/ # Every agent (TOOL_GUIDELINES.md, TOOL_SHELL[.windows].md)
|
|
15
|
+
│ │ └── root/ # Root agent only — empty by default; user-set
|
|
16
|
+
│ ├── agents/<id>/
|
|
17
|
+
│ │ ├── agent.yaml # Agent config
|
|
18
|
+
│ │ └── AGENT.md # Agent personality
|
|
19
|
+
│ ├── models/ # Model registry — one file per provider, scanned at startup
|
|
20
|
+
│ │ └── <providerId>.yaml # e.g. aws-bedrock-claude-invoke.yaml
|
|
21
|
+
│ ├── skills/<id>/
|
|
22
|
+
│ │ └── SKILL.md # Skill definition (frontmatter + body)
|
|
23
|
+
│ ├── internal-sessions/<agentId>/ # Internal-agent sessions (`__evo_agent__`, `__score__`, `__apply_agent__`)
|
|
24
|
+
│ │ # — global so they don't pollute any workspace's halo.db
|
|
25
|
+
│ │ └── <sessionId>.json
|
|
26
|
+
│ ├── evo.db # Cross-workspace evolution queue (evolution_runs + evolution_applies)
|
|
27
|
+
│ ├── cron.db # Cross-workspace cron jobs + run history (cron_jobs + cron_runs)
|
|
28
|
+
│ ├── logs/ # Runtime logs
|
|
29
|
+
│ │ ├── evo/ # Per-evo-run wrapper logs
|
|
30
|
+
│ │ └── cron/ # Per-cron-run cli stdout/stderr (30-day retention)
|
|
31
|
+
│ ├── server.lock # Single-instance pid lock
|
|
32
|
+
│ └── .template-version # Template-seed marker (used by ensureHaloHome)
|
|
33
|
+
├── secrets/ # Sensitive files (not mounted into sandbox)
|
|
34
|
+
│ ├── settings.yaml # Global settings (API keys, credentials)
|
|
35
|
+
│ ├── config.yaml # System config (admin password, server settings)
|
|
36
|
+
│ └── channels/
|
|
37
|
+
│ └── channels.db # Channel accounts DB
|
|
38
|
+
|
|
39
|
+
<workspace>/.halo/ # Workspace-level (overrides same-name global configs)
|
|
40
|
+
├── USER.md # Optional, overrides global
|
|
41
|
+
├── INSTRUCTIONS.md # Project-level instructions (overrides global INSTRUCTIONS.md)
|
|
42
|
+
├── INDEX.md # Project overview + doc index (always injected)
|
|
43
|
+
├── agents/<id>/ # Workspace agent (overrides same-id global)
|
|
44
|
+
├── skills/<id>/
|
|
45
|
+
├── prompts/ # System prompts (directory-level override of global)
|
|
46
|
+
│ ├── bootstrap/ # Overrides ~/.halo/global/prompts/bootstrap/ if present
|
|
47
|
+
│ ├── all/ # Overrides ~/.halo/global/prompts/all/ if present
|
|
48
|
+
│ └── root/ # Overrides ~/.halo/global/prompts/root/ if present
|
|
49
|
+
├── sessions/<agentId>/ # Session files (one per regular session)
|
|
50
|
+
├── memory/ # Project memory (dated entries)
|
|
51
|
+
├── logs/
|
|
52
|
+
├── evo/ # Self-evolution per-workspace artifacts
|
|
53
|
+
│ ├── runs/<id>/ # per-evaluation: source-snapshot.json, tool-flow.md,
|
|
54
|
+
│ │ # evo-context.json, sandbox/, patch.md, score.json,
|
|
55
|
+
│ │ # sub-cli.log, optional .skip.md
|
|
56
|
+
│ ├── applies/<id>/ # per-apply: meta.json, sandbox/, regress/<runId>/, apply.log
|
|
57
|
+
│ ├── history/apply-<id>/ # pre-apply rollback snapshot (MANIFEST.json + the overwritten files)
|
|
58
|
+
│ └── archive/ # zipped runs/applies past the retention window
|
|
59
|
+
├── tmp/ # Agent scratch files (logs, downloads, intermediate artifacts) — convention from TOOL_GUIDELINES, not auto-created
|
|
60
|
+
├── assets/<channel>/inbound/<accountId>/<date>/ # Inbound media per channel (image/voice/video/file)
|
|
61
|
+
├── halo.db # Per-workspace sqlite (sessions metadata, command registry, disabled-items)
|
|
62
|
+
└── docs/ # Project docs (requirements/design/dev/test/plans)
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Precedence: workspace > global, **at folder granularity**. For the same id, a workspace `agents/<id>/` or `skills/<id>/` folder entirely replaces the global one — every file in it, no per-file fallback to global (a workspace agent folder with only `AGENT.md` loses the global `agent.yaml`). Same whole-folder rule for `prompts/{bootstrap,all,root}/` (workspace scope directory replaces the global one). INSTRUCTIONS.md is the single-file exception: workspace root suppresses global.
|
|
66
|
+
|
|
67
|
+
### Path constructors
|
|
68
|
+
|
|
69
|
+
All `.halo/...` path math goes through `packages/server/src/paths.ts` (e.g. `wsHaloDir(ws)`, `wsEvoRunDir(ws, runId)`, `globalInternalSessionFile(agentId, seg)`, `cronLogFile(runId)`). Treat `paths.ts` as the canonical reference for the layout above; if the layout changes, update `paths.ts` first and call sites follow.
|
|
70
|
+
|
|
71
|
+
## Session file format (v1)
|
|
72
|
+
|
|
73
|
+
Path: `.halo/sessions/{agentId}/{sessionId}.json`
|
|
74
|
+
|
|
75
|
+
```jsonc
|
|
76
|
+
{
|
|
77
|
+
"version": 1,
|
|
78
|
+
"id": "oogezptkmoaeflb5",
|
|
79
|
+
"agentId": "default",
|
|
80
|
+
"agentName": "Default",
|
|
81
|
+
"title": "First user message...", // auto-generated, max 60 chars
|
|
82
|
+
"source": "explorer", // "explorer" (root) | "delegated" (sub-session)
|
|
83
|
+
"createdAt": "ISO8601",
|
|
84
|
+
"updatedAt": "ISO8601",
|
|
85
|
+
"messageCount": 42,
|
|
86
|
+
"contextTokens": 5975,
|
|
87
|
+
"totalOutputTokens": 6058,
|
|
88
|
+
"parentSessionId": "parent_id", // sub-sessions only
|
|
89
|
+
"messages": [SessionMessage], // UI event-log format (written by WS handler / UIState reducer)
|
|
90
|
+
"rawMessages": [AnthropicMessage], // raw Bedrock API shape (written by SessionManager saveAgentState)
|
|
91
|
+
"output": "..." // accumulated assistant text from the latest turn
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### SessionMessage
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
98
|
+
type MessageType =
|
|
99
|
+
| 'user' | 'assistant'
|
|
100
|
+
| 'tool_call' | 'tool_result'
|
|
101
|
+
| 'usage' | 'context'
|
|
102
|
+
| 'agent_start' | 'agent_done'
|
|
103
|
+
| 'notification'
|
|
104
|
+
|
|
105
|
+
interface SessionMessage {
|
|
106
|
+
// Required
|
|
107
|
+
id: string // "m_{timestamp36}_{counter36}"
|
|
108
|
+
type: MessageType
|
|
109
|
+
role: 'user' | 'assistant' | 'system'
|
|
110
|
+
content: string
|
|
111
|
+
timestamp: number // Unix ms
|
|
112
|
+
agentName: string
|
|
113
|
+
|
|
114
|
+
// Optional scope
|
|
115
|
+
taskId?: string // Sub-agent task ID
|
|
116
|
+
|
|
117
|
+
// assistant-only
|
|
118
|
+
toolCalls?: ToolCallEntry[]
|
|
119
|
+
contentBlocks?: ContentBlockEntry[]
|
|
120
|
+
|
|
121
|
+
// tool_call-only
|
|
122
|
+
toolName?: string
|
|
123
|
+
toolInput?: unknown
|
|
124
|
+
toolOutput?: unknown
|
|
125
|
+
durationMs?: number
|
|
126
|
+
|
|
127
|
+
// usage-only
|
|
128
|
+
turnId?: string // LLM call UUID
|
|
129
|
+
usage?: {
|
|
130
|
+
inputTokens, outputTokens, totalTokens
|
|
131
|
+
cacheReadInputTokens, cacheWriteInputTokens?
|
|
132
|
+
ttftMs?, e2eMs?, thinkingEffort?
|
|
133
|
+
}
|
|
134
|
+
modelId?: string
|
|
135
|
+
|
|
136
|
+
// context-only (not persisted)
|
|
137
|
+
systemPrompt?: string
|
|
138
|
+
|
|
139
|
+
// Transient (not persisted)
|
|
140
|
+
streaming?: boolean
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### ToolCallEntry
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
interface ToolCallEntry {
|
|
148
|
+
name: string
|
|
149
|
+
input: string // formatted summary
|
|
150
|
+
output?: string
|
|
151
|
+
durationMs?: number
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### ContentBlockEntry
|
|
156
|
+
|
|
157
|
+
Keeps the interleaved order of text and tool calls within one assistant turn.
|
|
158
|
+
|
|
159
|
+
```typescript
|
|
160
|
+
type ContentBlockEntry =
|
|
161
|
+
| { type: 'text'; text: string; turnId?: string }
|
|
162
|
+
| { type: 'thinking'; text: string; turnId?: string }
|
|
163
|
+
| { type: 'tool_call'; toolCall: ToolCallEntry; turnId?: string }
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
`turnId` uniquely identifies each LLM API call. Content blocks and the corresponding usage message in the same turn share the same turnId.
|
|
167
|
+
|
|
168
|
+
### Render rules
|
|
169
|
+
|
|
170
|
+
| Mode | Visible | Hidden |
|
|
171
|
+
|---|---|---|
|
|
172
|
+
| Normal | user, assistant, notification | tool_call, tool_result, usage, context, agent_start, agent_done |
|
|
173
|
+
| Debug | user, assistant, notification, context, agent_start, agent_done + inlined usage | tool_call, tool_result (already inlined in the assistant's contentBlocks) |
|
|
174
|
+
|
|
175
|
+
Assistant rendering priority:
|
|
176
|
+
1. Has `contentBlocks` → render in contentBlocks order
|
|
177
|
+
2. No contentBlocks, has `toolCalls` → tools first, then content (legacy)
|
|
178
|
+
3. Neither → render only `content`
|
|
179
|
+
|
|
180
|
+
### Backwards compatibility
|
|
181
|
+
|
|
182
|
+
1. Missing `type`: infer from `role` + existing fields
|
|
183
|
+
2. Missing `contentBlocks`: fall back to the `toolCalls` + `content` split layout
|
|
184
|
+
3. Missing `version`: treat as v0, apply inference rules
|
|
185
|
+
|
|
186
|
+
### Change rules
|
|
187
|
+
|
|
188
|
+
- Format changes **must** bump `version`
|
|
189
|
+
- Readers **must** handle every historical version
|
|
190
|
+
- Persisted fields **must not** be removed
|
|
191
|
+
- Adding optional fields does **not** require a version bump
|
|
192
|
+
|
|
193
|
+
## Agent Config format
|
|
194
|
+
|
|
195
|
+
### agent.yaml
|
|
196
|
+
|
|
197
|
+
```yaml
|
|
198
|
+
name: Default # required
|
|
199
|
+
description: Default agent # optional
|
|
200
|
+
model:
|
|
201
|
+
provider: aws-bedrock-claude-invoke # matches ~/.halo/global/models/<providerId>.yaml
|
|
202
|
+
id: global.anthropic.claude-sonnet-4-6
|
|
203
|
+
endpoint: https://bedrock-runtime.us-west-2.amazonaws.com # full endpoint URL; supports custom proxy
|
|
204
|
+
maxTokens: 16384 # optional, model's max output tokens
|
|
205
|
+
thinking:
|
|
206
|
+
enabled: true
|
|
207
|
+
effort: medium # optional: low/medium/high/xhigh/max
|
|
208
|
+
budget: medium # optional legacy alias for effort
|
|
209
|
+
promptCaching: 1h # true / '5m' / '1h'
|
|
210
|
+
system_prompt: > # AGENT.md wins if present
|
|
211
|
+
You are...
|
|
212
|
+
context:
|
|
213
|
+
maxTokens: 200000 # context window cap
|
|
214
|
+
compressAt: 0.8 # auto-compact threshold (default; settings: general.compact.compress_at)
|
|
215
|
+
tools:
|
|
216
|
+
- file_read
|
|
217
|
+
- file_write
|
|
218
|
+
- shell_exec
|
|
219
|
+
skills:
|
|
220
|
+
- agent-creator
|
|
221
|
+
priority: 99 # sort weight (higher first); default 0
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
TypeScript type (`packages/server/src/agents/agent-loader.ts`):
|
|
225
|
+
|
|
226
|
+
```typescript
|
|
227
|
+
interface AgentYamlConfig {
|
|
228
|
+
name: string
|
|
229
|
+
description?: string
|
|
230
|
+
model?: {
|
|
231
|
+
provider?: string // required — no default fallback
|
|
232
|
+
id?: string // required — no default fallback
|
|
233
|
+
endpoint?: string // required — no default fallback
|
|
234
|
+
maxTokens?: number
|
|
235
|
+
promptCaching?: boolean | string
|
|
236
|
+
thinking?: { enabled?: boolean; budget?: string; effort?: string }
|
|
237
|
+
}
|
|
238
|
+
system_prompt?: string
|
|
239
|
+
tools?: string[]
|
|
240
|
+
skills?: string[]
|
|
241
|
+
context?: { maxTokens?: number; compressAt?: number }
|
|
242
|
+
priority?: number
|
|
243
|
+
}
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### AGENT.md
|
|
247
|
+
|
|
248
|
+
Path: `.halo/agents/{agent-id}/AGENT.md`
|
|
249
|
+
|
|
250
|
+
Plain Markdown describing the agent's personality, behaviour, and constraints. **Takes precedence over** the `system_prompt` field in `agent.yaml`.
|
|
251
|
+
|
|
252
|
+
### Load precedence
|
|
253
|
+
|
|
254
|
+
1. `{workspace}/.halo/agents/{id}/` — workspace
|
|
255
|
+
2. `~/.halo/global/agents/{id}/` — global
|
|
256
|
+
|
|
257
|
+
**Whole-folder override.** Resolution is by the agent's **folder**, not by
|
|
258
|
+
individual files: if the workspace dir `{workspace}/.halo/agents/{id}/`
|
|
259
|
+
exists, the agent is served entirely from it — both `agent.yaml` and
|
|
260
|
+
`AGENT.md` — and the global folder is ignored. A file missing inside the
|
|
261
|
+
workspace folder is simply absent; there is **no per-file fallback** to
|
|
262
|
+
global (a workspace agent with only `AGENT.md` has no `agent.yaml`, hence
|
|
263
|
+
no model config). When the workspace folder doesn't exist, the agent is
|
|
264
|
+
served entirely from global.
|
|
265
|
+
|
|
266
|
+
## Settings format
|
|
267
|
+
|
|
268
|
+
Path: `~/.halo/secrets/settings.yaml` (global) / `<workspace>/.halo/settings.yaml` (workspace overlay).
|
|
269
|
+
|
|
270
|
+
Layout follows VSCode's `contributes.configuration` model: schema lives with each declarer (provider yaml, skill yaml, server built-ins); only the values live in `settings.yaml`. Full spec: [requirements/settings.md](../requirements/settings.md).
|
|
271
|
+
|
|
272
|
+
```yaml
|
|
273
|
+
# Top-level keys are namespace ids; nested keys are kind (`params` / `secrets`)
|
|
274
|
+
# then leaf key.
|
|
275
|
+
|
|
276
|
+
general: # built-in declarer (the server itself)
|
|
277
|
+
session:
|
|
278
|
+
max_queue_size: 256
|
|
279
|
+
max_nesting_depth: 16
|
|
280
|
+
compact:
|
|
281
|
+
keep_messages: 5
|
|
282
|
+
max_summary_input: 15000
|
|
283
|
+
max_message_slice: 800
|
|
284
|
+
summarize_timeout_sec: 300
|
|
285
|
+
sandbox:
|
|
286
|
+
hidden_dirs: "~/.halo/secrets,~/.aws,~/.ssh,~/.gnupg,~/.docker"
|
|
287
|
+
hidden_files: "~/.npmrc,~/.bash_history,~/.gitconfig"
|
|
288
|
+
logging:
|
|
289
|
+
level: warn
|
|
290
|
+
|
|
291
|
+
aws-bedrock-claude-invoke: # provider id (matches models/<id>.yaml)
|
|
292
|
+
secrets:
|
|
293
|
+
access_key_id: AKIA…
|
|
294
|
+
secret_access_key: <<AWS_SECRET_ACCESS_KEY>>
|
|
295
|
+
|
|
296
|
+
kimi:
|
|
297
|
+
secrets:
|
|
298
|
+
api_key: <<KIMI_API_KEY>>
|
|
299
|
+
|
|
300
|
+
tavily-web-search: # skill id (matches skills/<id>/)
|
|
301
|
+
params:
|
|
302
|
+
api_key: <<TAVILY_API_KEY>>
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
Path conventions:
|
|
306
|
+
- `general.<key>` — built-in server knobs (the only namespace that doesn't follow `<id>.<kind>s.<key>`)
|
|
307
|
+
- `<provider-id>.secrets.<key>` — server-side credentials for a model provider
|
|
308
|
+
- `<skill-id>.params.<key>` — values an agent can reference via `{{<skill-id>.params.<key>}}`
|
|
309
|
+
- `<skill-id>.secrets.<key>` — server-side keys a skill needs but agents must not see
|
|
310
|
+
|
|
311
|
+
### Load precedence
|
|
312
|
+
|
|
313
|
+
```
|
|
314
|
+
process env (via <<ENV>>) > workspace settings.yaml > global settings.yaml > schema default
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
Workspace `settings.yaml` deep-merges over global, leaf by leaf. The Settings page surfaces source per field (`workspace` / `inherited from global` / `unset`) and lets users reset a workspace override.
|
|
318
|
+
|
|
319
|
+
### Env-var interpolation: `<<ENV_NAME>>`
|
|
320
|
+
|
|
321
|
+
A value of the form `<<ENV_NAME>>` is replaced at read time with `process.env.ENV_NAME`. **If the env var is unset, the literal `<<ENV_NAME>>` stays verbatim** — calls fail loudly with the placeholder visible, instead of silently falling through to a different env var. This is intentional: it makes typos discoverable.
|
|
322
|
+
|
|
323
|
+
`<<>>` substitution is honored only inside settings-resolved values; cmd text the agent itself writes is **not** scanned (`shell_exec "echo <<HOME>>"` keeps the literal). Trust boundary is "settings file content", not "string happens to look like a placeholder".
|
|
324
|
+
|
|
325
|
+
### Built-in keys (declared by the server)
|
|
326
|
+
|
|
327
|
+
| Path | Default | Notes |
|
|
328
|
+
|---|---|---|
|
|
329
|
+
| `general.session.max_queue_size` | 256 | Max queued messages per session |
|
|
330
|
+
| `general.session.max_nesting_depth` | 16 | Sub-session nesting cap |
|
|
331
|
+
| `general.compact.keep_messages` | 5 | Recent messages kept intact during compaction |
|
|
332
|
+
| `general.compact.max_summary_input` | 15000 | Local truncation fallback total char cap |
|
|
333
|
+
| `general.compact.max_message_slice` | 800 | Local truncation per-message char cap |
|
|
334
|
+
| `general.compact.summarize_timeout_sec` | 300 | LLM summary timeout |
|
|
335
|
+
| `general.limits.shell_output_bytes` | 5242880 | Max bytes captured from one `shell_exec` (stdout+stderr); excess truncated with a `[truncated]` marker |
|
|
336
|
+
| `general.limits.web_fetch_bytes` | 51200 | Max bytes downloaded by one `web_fetch` |
|
|
337
|
+
| `general.limits.grep_default_matches` | 50 | Default `grep` match cap when no explicit `max` is passed |
|
|
338
|
+
| `general.limits.tool_result_render_chars` | 8000 | Per-tool-result cap on the content **fed to the LLM** (truncated with a re-run marker to protect the context window / prompt cache). The UI gets a much larger slice — see `tool_result_ui_chars` and `agent-loop.ts` (`resultContent` = LLM cap, `resultTextFull` = UI cap) |
|
|
339
|
+
| `general.limits.tool_result_ui_chars` | 65536 | Per-tool-result cap on the content **stored for UI display** (admin/web chat panel). Far larger than the LLM cap so a normal command's full output stays visible, but bounded so a multi-MB `cat` can't bloat the session file / WS payload / browser render; excess truncated with a marker pointing at `file_read` |
|
|
340
|
+
| `general.limits.ws_event_buffer` | 5000 | Events buffered per detached WS session before oldest are dropped on reattach |
|
|
341
|
+
| `general.limits.terminal_scrollback_bytes` | 50000 | Off-screen scrollback bytes retained per detached persistent terminal |
|
|
342
|
+
| `general.sandbox.hidden_dirs` | `~/.halo/secrets,~/.aws,~/.ssh,~/.gnupg,~/.docker` | bwrap tmpfs overlay (Linux only) |
|
|
343
|
+
| `general.sandbox.hidden_files` | `~/.npmrc,~/.bash_history,~/.gitconfig` | bwrap /dev/null bind (Linux only) |
|
|
344
|
+
| `general.logging.level` | warn | `debug` / `info` / `warn` / `error` |
|
|
345
|
+
|
|
346
|
+
Schema source: [packages/server/src/settings-schema.ts](../../../packages/server/src/settings-schema.ts) `generalSection()`.
|
|
347
|
+
|
|
348
|
+
### Caching
|
|
349
|
+
|
|
350
|
+
`config.ts` reads settings.yaml lazily with mtime-watching: every read stats the file and reparses if mtime changed. UI saves bump mtime, so the server picks up new values on the next read **without a restart**.
|
|
351
|
+
|
|
352
|
+
### Orphans
|
|
353
|
+
|
|
354
|
+
Values present in `settings.yaml` whose namespace isn't currently declared by any provider/skill are surfaced as **orphans** in the Settings UI. They aren't deleted automatically — uninstalling a skill keeps its values around so re-installing pops them back in. Users prune them via the orphan tab.
|
|
355
|
+
|
|
356
|
+
> There is no longer a global "file access level" setting. Per-session access level is tracked on the session itself (`agent_sessions.access_level`) and, for channel bots, on the account (`channel_accounts.access_level`).
|
|
357
|
+
|
|
358
|
+
## Model registry format
|
|
359
|
+
|
|
360
|
+
Path: `~/.halo/global/models/<providerId>.yaml` — one file per provider. All files are scanned at startup and merged into the in-memory registry. The same yaml also declares the provider's required server-side credentials (`secrets:` section), which the Settings page renders.
|
|
361
|
+
|
|
362
|
+
```yaml
|
|
363
|
+
# aws-bedrock-claude-invoke.yaml
|
|
364
|
+
id: aws-bedrock-claude-invoke # required, must match filename and agent.yaml model.provider
|
|
365
|
+
displayName: AWS Bedrock Claude (Invoke API) # shown in UI
|
|
366
|
+
displayName_zh: AWS Bedrock Claude(Invoke API) # optional zh override
|
|
367
|
+
description: Invokes Bedrock via InvokeModel (non-streaming)
|
|
368
|
+
description_zh: 通过 Bedrock InvokeModel(非流式)调用
|
|
369
|
+
defaultEndpoint: https://bedrock-runtime.us-west-2.amazonaws.com
|
|
370
|
+
defaultModelId: global.anthropic.claude-sonnet-4-6 # picked when user switches to this provider
|
|
371
|
+
endpointPresets:
|
|
372
|
+
- https://bedrock-runtime.us-west-2.amazonaws.com
|
|
373
|
+
- https://bedrock-runtime.us-east-1.amazonaws.com
|
|
374
|
+
|
|
375
|
+
# Server-side credentials. Stored at <provider-id>.secrets.<key> in
|
|
376
|
+
# settings.yaml; never injected into agent prompts or shell_exec.
|
|
377
|
+
secrets:
|
|
378
|
+
- key: access_key_id
|
|
379
|
+
description: AWS Access Key ID. Leave empty to use the AWS credential chain.
|
|
380
|
+
description_zh: AWS Access Key ID。留空则使用凭证链
|
|
381
|
+
secret: true
|
|
382
|
+
- key: secret_access_key
|
|
383
|
+
description: AWS Secret Access Key.
|
|
384
|
+
description_zh: AWS Secret Access Key
|
|
385
|
+
secret: true
|
|
386
|
+
|
|
387
|
+
models:
|
|
388
|
+
- id: global.anthropic.claude-sonnet-4-6
|
|
389
|
+
displayName: Claude Sonnet 4.6
|
|
390
|
+
maxOutputTokens: 64000
|
|
391
|
+
capabilities:
|
|
392
|
+
image: true # supports image input
|
|
393
|
+
video: false
|
|
394
|
+
audio: false
|
|
395
|
+
promptCaching:
|
|
396
|
+
default: 1h # auto-on value when toggled / on provider switch
|
|
397
|
+
ttlPresets:
|
|
398
|
+
- { value: 5m, label: 5min }
|
|
399
|
+
- { value: 1h, label: 1hour }
|
|
400
|
+
thinking:
|
|
401
|
+
mode: adaptive # 'adaptive' | 'manual'
|
|
402
|
+
defaultEnabled: true # start with Thinking checked for new agents
|
|
403
|
+
default: medium # effort selected when Thinking is on (adaptive)
|
|
404
|
+
defaultBudgetTokens: 4000 # budget when Thinking is on (manual mode only)
|
|
405
|
+
effortPresets:
|
|
406
|
+
- { value: low, label: Low }
|
|
407
|
+
- { value: medium, label: Medium }
|
|
408
|
+
- { value: high, label: High }
|
|
409
|
+
- { value: max, label: Max }
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
### Capability defaults — what each `default*` field controls
|
|
413
|
+
|
|
414
|
+
| Path | Used when | Fallback |
|
|
415
|
+
|---|---|---|
|
|
416
|
+
| `<provider>.defaultModelId` | User switches provider; form picks this model | `models[0].id` |
|
|
417
|
+
| `<provider>.defaultEndpoint` | Same; endpoint input | `''` |
|
|
418
|
+
| `capabilities.promptCaching.default` | Toggle on / provider switch into a caching-capable model | `ttlPresets[0].value` |
|
|
419
|
+
| `capabilities.thinking.defaultEnabled` | New agent or provider switch with no prior thinking config | `false` |
|
|
420
|
+
| `capabilities.thinking.default` | Thinking toggled on, adaptive mode | `effortPresets[0].value` |
|
|
421
|
+
| `capabilities.thinking.defaultBudgetTokens` | Thinking toggled on, manual mode | `8192` |
|
|
422
|
+
|
|
423
|
+
Existing agent yaml values always win over these defaults — switching providers carries the user's effort/ttl over when valid for the new model. The defaults only fire when there's nothing to carry, or the carry-over isn't valid in the new vocabulary (e.g. Bedrock `medium` → Kimi `enabled/disabled` mismatch resets to the new provider's `default`).
|
|
424
|
+
|
|
425
|
+
**`capabilities` drives the UI and runtime behavior**:
|
|
426
|
+
- `image` / `video` / `audio` (boolean) → modality badges in the form; at runtime, unsupported modality inputs are filtered out with a text notice instead of causing API errors
|
|
427
|
+
- `promptCaching.ttlPresets` → Prompt Caching dropdown
|
|
428
|
+
- `thinking.mode`:
|
|
429
|
+
- `adaptive` → wire format `thinking: {type: 'adaptive'}` + `output_config.effort` (Sonnet 4.6 / Opus 4.6+ / Opus 4.7)
|
|
430
|
+
- `manual` → wire format `thinking: {type: 'enabled', budget_tokens: N}` (Haiku 4.5 and other legacy thinking models). UI offers a budget number input; runtime translates effort labels via the table in `bedrock-agent.ts` if needed.
|
|
431
|
+
- `thinking.effortPresets` → Thinking effort dropdown (when `mode: adaptive`)
|
|
432
|
+
- Omit a block → the UI hides that control for this model
|
|
433
|
+
|
|
434
|
+
**`secrets:` declarations** drive the Settings page: each entry becomes a masked input grouped under the provider's display name. Values land at `<provider-id>.secrets.<key>` in settings.yaml.
|
|
435
|
+
|
|
436
|
+
`agent.yaml`'s `model.provider` must match a provider's `id` — otherwise session spawn fails.
|
|
437
|
+
|
|
438
|
+
Routing: `createModelRuntime(providerId, cfg)` → looks up the implementation by `providerId`. See [design/agent.md](../design/agent.md#agent-instance).
|
|
439
|
+
|
|
440
|
+
## Skill schema (`config.yaml`)
|
|
441
|
+
|
|
442
|
+
Optional file at `<skill-dir>/config.yaml` (next to `SKILL.md`). Declares which params and secrets the skill needs; the Settings page renders these grouped under the skill's display name.
|
|
443
|
+
|
|
444
|
+
```yaml
|
|
445
|
+
# tavily-web-search/config.yaml
|
|
446
|
+
displayName_zh: Tavily 联网搜索 # optional override; falls back to SKILL.md `name`
|
|
447
|
+
description: Real-time web search via Tavily Search API.
|
|
448
|
+
description_zh: 通过 Tavily 搜索 API 进行实时联网搜索。
|
|
449
|
+
|
|
450
|
+
params: # values an agent can use via {{<skill>.params.<key>}}
|
|
451
|
+
- key: api_key
|
|
452
|
+
description: Tavily Search API Key
|
|
453
|
+
description_zh: Tavily 搜索 API Key
|
|
454
|
+
default: <<TAVILY_API_KEY>> # placeholder/hint; user can leave as-is to use env var
|
|
455
|
+
secret: true # masked input + masked API responses
|
|
456
|
+
|
|
457
|
+
secrets: [] # optional — server-only keys, never reach the agent
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
Skill bodies can use the **short form** `{{params.<key>}}` — the activation pipeline rewrites it to `{{<skill-id>.params.<key>}}` before handing the body to the agent. Long form (`{{nano-banana.params.endpoint}}`) is also accepted, useful when one skill needs to reference another skill's param. AGENT.md must use the long form.
|
|
461
|
+
|
|
462
|
+
## Skill format
|
|
463
|
+
|
|
464
|
+
Path: `.halo/skills/{skill-id}/SKILL.md`
|
|
465
|
+
|
|
466
|
+
```markdown
|
|
467
|
+
---
|
|
468
|
+
name: skill-id # kebab-case, = directory name
|
|
469
|
+
description: One-line description for agent discovery
|
|
470
|
+
command: /review # optional, explicit opt-in registers a slash command
|
|
471
|
+
---
|
|
472
|
+
|
|
473
|
+
# Skill Title
|
|
474
|
+
|
|
475
|
+
Detailed instructions...
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
```typescript
|
|
479
|
+
interface SkillMeta {
|
|
480
|
+
id: string // directory name
|
|
481
|
+
name: string // from frontmatter
|
|
482
|
+
description: string // from frontmatter
|
|
483
|
+
path: string // absolute path to SKILL.md
|
|
484
|
+
}
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
Load precedence matches agents: workspace > global, **whole-folder override**. A workspace `skills/<id>/` folder replaces the global skill wholesale — SKILL.md plus every sibling resource file — with no per-file fallback to global.
|
|
488
|
+
|
|
489
|
+
## SQLite databases
|
|
490
|
+
|
|
491
|
+
Workspace DB: `<workspace>/.halo/halo.db`
|
|
492
|
+
Channel DB: `~/.halo/secrets/channels/channels.db`
|
|
493
|
+
Schema seed: `packages/server/templates/schema.sql`
|
|
494
|
+
ORM: `packages/server/src/db/schema.ts`, `packages/server/src/db/channel-db.ts`
|
|
495
|
+
|
|
496
|
+
The databases hold session metadata indexes and workspace-scoped preferences (e.g. disabled items); message content lives in JSON files. Agent/skill/project config goes through the filesystem.
|
|
497
|
+
|
|
498
|
+
### Tables
|
|
499
|
+
|
|
500
|
+
**`sessions`** — frontend session index (created on first chat)
|
|
501
|
+
|
|
502
|
+
| Column | Type | Notes |
|
|
503
|
+
|---|---|---|
|
|
504
|
+
| id | TEXT PK | Session ID |
|
|
505
|
+
| title | TEXT NOT NULL DEFAULT '' | Truncated first user message |
|
|
506
|
+
| messages | TEXT | Legacy field, unused (content now in JSON) |
|
|
507
|
+
| message_count | INTEGER | Message count |
|
|
508
|
+
| created_at / updated_at | INTEGER | Unix ms |
|
|
509
|
+
|
|
510
|
+
**`agent_sessions`** — agent session index (root + sub-sessions)
|
|
511
|
+
|
|
512
|
+
| Column | Type | Notes |
|
|
513
|
+
|---|---|---|
|
|
514
|
+
| id | TEXT PK | Session ID (hierarchical: `sid_abc` or `sid_abc>sid_def`) |
|
|
515
|
+
| parent_id | TEXT | Parent session ID (null = root) |
|
|
516
|
+
| agent_id | TEXT NOT NULL | Agent YAML ID |
|
|
517
|
+
| agent_name | TEXT | Display name |
|
|
518
|
+
| description | TEXT | Task description |
|
|
519
|
+
| working_dir | TEXT | Workspace-relative path; null = project root |
|
|
520
|
+
| access_level | TEXT | `'readonly'`, `'workspace'`, or null (null = full access). Added via idempotent ALTER in `db/index.ts`. |
|
|
521
|
+
| created_at / updated_at | INTEGER | Unix ms |
|
|
522
|
+
| stopped_at | INTEGER | Stopped timestamp (null = active) |
|
|
523
|
+
| archived_at | INTEGER | Archived timestamp (null = not archived) |
|
|
524
|
+
|
|
525
|
+
**`disabled_items`** — per-workspace disable state for agents and skills (allows the same global item to be independently toggled in each workspace)
|
|
526
|
+
|
|
527
|
+
| Column | Type | Notes |
|
|
528
|
+
|---|---|---|
|
|
529
|
+
| item_type | TEXT NOT NULL | `'agent'` or `'skill'` |
|
|
530
|
+
| item_id | TEXT NOT NULL | Agent/skill ID |
|
|
531
|
+
| scope | TEXT NOT NULL | `'global'` or `'workspace'` — which source the item comes from |
|
|
532
|
+
| disabled_at | INTEGER NOT NULL | Unix ms |
|
|
533
|
+
| | | **PK**: `(item_type, item_id, scope)` |
|
|
534
|
+
|
|
535
|
+
**`channel_accounts`** — unified channel account index (lives in `~/.halo/secrets/channels/channels.db`)
|
|
536
|
+
|
|
537
|
+
All channel types (telegram, web, wechat, slack, feishu) share one table. Common fields are explicit columns; channel-specific fields live in the `config` JSON column.
|
|
538
|
+
|
|
539
|
+
| Column | Type | Notes |
|
|
540
|
+
|---|---|---|
|
|
541
|
+
| account_id | TEXT PK | Channel-specific ID (e.g. `halo_agent_bot`, `abc-im-bot`, `e718bb7b`) |
|
|
542
|
+
| channel_type | TEXT NOT NULL | `'telegram'`, `'web'`, `'wechat'`, `'slack'`, or `'feishu'` |
|
|
543
|
+
| workspace_path | TEXT NOT NULL | Absolute path of the bound workspace |
|
|
544
|
+
| label | TEXT | User-chosen name |
|
|
545
|
+
| enabled | INTEGER | 1 = active, 0 = disabled |
|
|
546
|
+
| access_level | TEXT | `'full'`, `'workspace'`, or `'readonly'` (default `'readonly'`) |
|
|
547
|
+
| language | TEXT | `'en'` or `'zh'` (default `'en'`) |
|
|
548
|
+
| config | TEXT | JSON — channel-specific fields (see below) |
|
|
549
|
+
| created_at / updated_at | INTEGER | Unix ms |
|
|
550
|
+
|
|
551
|
+
**Config JSON by channel type:**
|
|
552
|
+
|
|
553
|
+
| Channel | Config fields |
|
|
554
|
+
|---|---|
|
|
555
|
+
| telegram | `botToken`, `botUsername`, `allowedUsers` |
|
|
556
|
+
| web | `token` |
|
|
557
|
+
| wechat | `botToken`, `baseUrl`, `userId`, `syncBuf` |
|
|
558
|
+
| slack | `botToken`, `appToken`, `botUserId`, `teamId` |
|
|
559
|
+
| feishu | `appId`, `appSecret`, `verificationToken`, `encryptKey`, `botOpenId` |
|
|
560
|
+
|
|
561
|
+
### Schema change rules
|
|
562
|
+
|
|
563
|
+
- Add columns via `ALTER TABLE ... ADD COLUMN` + try/catch (skip if already present)
|
|
564
|
+
- Do not drop or rename existing columns
|
|
565
|
+
- New tables: add to `templates/schema.sql`
|
|
566
|
+
- Centralise migration logic in `db/index.ts` and `db/channel-db.ts`
|
|
567
|
+
- New channel types: add rows with a new `channel_type` value + define config shape in the channel's `accounts.ts` adapter
|
|
568
|
+
|
|
569
|
+
## Changelog
|
|
570
|
+
|
|
571
|
+
| Version | Date | Change |
|
|
572
|
+
|---|---|---|
|
|
573
|
+
| v1 | 2026-04-22 | Initial protocol. SessionMessage gains `type`; SessionFileData gains `version`. |
|
|
574
|
+
| v1+ | 2026-04-22 | Optional additions: `thinking` ContentBlockEntry; usage fields `thinkingEffort`, `cacheWriteInputTokens`; agent.yaml `thinking`, `promptCaching`; `is_main` → `is_default`; path `explorer/main/` → `explorer/default/`. |
|
|
575
|
+
| v1+ | 2026-04-28 | Model registry reshaped from `models.yaml` to per-provider files under `models/`. Provider id `bedrock` renamed to `aws-bedrock-claude-invoke`. Added `agent_sessions.access_level` column; added `weixin_accounts.access_level` and `weixin_accounts.sync_buf`. Removed global file-access setting. |
|
|
576
|
+
| v1+ | 2026-05-12 | Restructured `~/.halo/`: sensitive files (settings.yaml, config.yaml, channels/) moved to `secrets/`; non-sensitive config remains in `global/`. `migrateSecrets()` auto-migrates on first startup. Access level expanded to three tiers: `full` / `workspace` / `readonly` (agent_sessions + channel_accounts). Tool execution routed through bwrap sandbox for non-full access levels. `agent_sessions.working_dir` now stored as workspace-relative path. |
|
|
577
|
+
| v1+ | 2026-05-13 | Settings i18n + UI polish: compact keys renamed camelCase → snake_case (`keep_messages`, `max_summary_input`, `max_message_slice`, `summarize_timeout_sec`). Added `description_zh` on all leaf nodes and `description`/`description_zh` on branch nodes (replaces `_hint`/`_hint_zh`). Added `secret: true` attribute for masked input. Added Tavily to default params. Admin UI fully i18n'd (agents, skills, settings, nav). |
|
|
578
|
+
| v1+ | 2026-05-13 | Added `packages/cli` — standalone CLI/TUI client with embedded agent loop (no server required). Imports server agent-core via subpath exports. Session prefix: `cli_`. Added `exports` + `typesVersions` to server `package.json`. |
|