@turmind/halo 0.2.1 → 0.2.2
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/README.md +109 -46
- package/admin-out/404.html +1 -1
- package/admin-out/index.html +1 -1
- package/admin-out/index.txt +1 -1
- package/bundled-docs/design/agentcore.md +97 -0
- package/bundled-docs/design/evolution.md +2 -2
- package/bundled-docs/design/halo-city.md +18 -5
- package/bundled-docs/design/storage.md +4 -4
- package/bundled-docs/design/web.md +10 -8
- package/bundled-docs/dev/api.md +3 -1
- package/bundled-docs/dev/deploy.md +10 -0
- package/bundled-docs/dev/env.md +3 -2
- package/bundled-docs/dev/tools.md +4 -3
- package/bundled-docs/guide/channels/web.md +2 -0
- package/bundled-docs/requirements/settings.md +10 -3
- package/dist/index.js +986 -341
- package/package.json +1 -1
- /package/admin-out/_next/static/{iSrc6429pyTB0lK-EE5oH → vHdygDsxwoyxkXg5umpZ1}/_buildManifest.js +0 -0
- /package/admin-out/_next/static/{iSrc6429pyTB0lK-EE5oH → vHdygDsxwoyxkXg5umpZ1}/_ssgManifest.js +0 -0
package/README.md
CHANGED
|
@@ -6,49 +6,119 @@
|
|
|
6
6
|
|
|
7
7
|
[English](README.md) | [中文](README.zh-CN.md)
|
|
8
8
|
|
|
9
|
-
**
|
|
9
|
+
**Throw in an idea. A team of agents builds it.**
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
Halo is a multi-agent workspace you drive in plain language. A primary agent reads your intent, breaks the work down, and fans it out to sub-agents that run in parallel — while every reasoning step and tool call streams by live, and you interrupt, redirect, or take over whenever you like. Everything the team knows and produces is plain files in a workspace you can read, edit, `git clone`, and share. No hidden memory. No opaque state.
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+

|
|
14
|
+
<p align="center"><sub>One prompt — <i>“Build a landing page for our coffee roastery… split the sections across sub-agents in parallel, then assemble.”</i> Executors fan out, report back, and the assembled page previews in Canvas, all in one browser tab.</sub></p>
|
|
14
15
|
|
|
15
|
-
|
|
16
|
+
## Install
|
|
16
17
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
```bash
|
|
19
|
+
npm install -g @turmind/halo # one binary, all subcommands
|
|
20
|
+
halo setup # interactive: password / port / model keys / optional skills
|
|
21
|
+
halo server start # → open http://localhost:9527
|
|
22
|
+
```
|
|
20
23
|
|
|
21
|
-
|
|
24
|
+
> [!IMPORTANT]
|
|
25
|
+
> **First message fails with `Could not load credentials from any providers`?** API keys entered during `halo setup` are stored but **not auto-bound to any agent** — the built-in `default` agent initially points at AWS Bedrock. Open **Agents → default** in the admin and switch its model provider to the one you configured. (Bedrock users with a working AWS credential chain are unaffected.) Details in [Quick Start](#quick-start).
|
|
22
26
|
|
|
23
|
-
|
|
27
|
+
## Why Halo
|
|
24
28
|
|
|
25
|
-
|
|
29
|
+
### 🧬 It rewrites its own prompts — and you review the diff
|
|
26
30
|
|
|
27
|
-
|
|
31
|
+
Halo learns from its own conversations. Run `/evo` (or let pre-compact trigger it): an internal evolution agent analyzes the session, drafts a patch to the workspace's own prompt files, dry-runs the patched agent in a sandbox against the original scenario, and a scoring agent grades the outcome. You approve or reject in the **Evolution** tab; approved patches merge back into the workspace. Real file diffs reviewed by you — not silent fine-tuning.
|
|
28
32
|
|
|
29
|
-
|
|
33
|
+

|
|
34
|
+
<p align="center"><sub>A real run awaiting review: lint / behavior / scope scores, the grader's reasoning, and the patch itself — one click merges it into the workspace.</sub></p>
|
|
30
35
|
|
|
31
|
-
|
|
36
|
+
### 📁 The whole agent team is one folder
|
|
32
37
|
|
|
33
|
-
|
|
38
|
+
Personas, skills, knowledge, session history — the entire agent team lives under `.halo/` as plain files:
|
|
34
39
|
|
|
35
|
-
```bash
|
|
36
|
-
npm install -g @turmind/halo
|
|
37
|
-
halo setup # interactive: password / port / model keys / optional skills
|
|
38
|
-
halo server start # launch on :9527 (default)
|
|
39
40
|
```
|
|
41
|
+
my-project/
|
|
42
|
+
├─ .halo/
|
|
43
|
+
│ ├─ agents/ # who's on the team — persona, model, tools per agent
|
|
44
|
+
│ ├─ skills/ # what they can do — markdown, injected on demand
|
|
45
|
+
│ ├─ docs/ # what they've learned — knowledge they read & write
|
|
46
|
+
│ ├─ memory/ # dated decision notes
|
|
47
|
+
│ └─ sessions/ # every conversation, replayable
|
|
48
|
+
└─ src/ … # your actual project
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
`git clone` the workspace and the recipient gets a complete, runnable agent team — not an export, the real thing. It's also what makes self-evolution possible: the evolution agent edits real files, and you review real diffs.
|
|
52
|
+
|
|
53
|
+
### 🌐 One workspace, every screen
|
|
54
|
+
|
|
55
|
+
Kick off a build in the browser, check progress from WeChat on the metro, drop a follow-up in Telegram or Slack, finish in the terminal. Every channel connects to the *same* workspace and session — channels are doors, the workspace is the room.
|
|
56
|
+
|
|
57
|
+
<p align="center">
|
|
58
|
+
<img src="assets/wechat-phone.jpg" alt="Halo in WeChat" width="270" />
|
|
59
|
+
|
|
60
|
+
<img src="assets/telegram-phone.jpg" alt="Halo in Telegram" width="270" />
|
|
61
|
+
</p>
|
|
62
|
+
<p align="center"><sub>The same workspace, continued from WeChat and Telegram on a phone.</sub></p>
|
|
63
|
+
|
|
64
|
+
### 👁 Watch it think
|
|
65
|
+
|
|
66
|
+
Every reasoning step, tool call, and file change streams in real time — including inside sub-agents. Interrupts are graceful (conversation repair, not a hard kill), and sub-agents report back when done. You stay in the loop instead of running and praying.
|
|
67
|
+
|
|
68
|
+

|
|
69
|
+
<p align="center"><sub>The primary agent fans out three executors in parallel — every <code>start_session</code> and tool call visible as it happens.</sub></p>
|
|
70
|
+
|
|
71
|
+
And when you'd rather have ambience than logs: [Halo City](#halo-city) renders the same runtime as a living pixel town.
|
|
72
|
+
|
|
73
|
+
## Also in the box
|
|
74
|
+
|
|
75
|
+
- **11 model providers, one runtime** — provider and model set per-agent: Claude on Bedrock for the heavy lifting, a cheap regional model for routine sub-tasks. No code changes.
|
|
76
|
+
- **IDE-grade admin** — chat + Monaco editor + file explorer + git panel + terminal (xterm.js) in one browser tab.
|
|
77
|
+
- **Skills** — markdown skill definitions injected into prompts on demand; workspace-scoped or global, no code required.
|
|
78
|
+
- **Cron tasks** — scheduled agent runs (recurring or one-shot) whose output fans out to your chat channels.
|
|
79
|
+
- **Permission isolation** — `full` / `workspace` / `readonly` access levels enforced by a bubblewrap sandbox (filesystem only — see [Status & Limitations](#status--limitations)).
|
|
80
|
+
- **ACP adapter** — plug a halo workspace into Claude Code as a native ACP agent, or let one halo delegate to another.
|
|
81
|
+
- **Structured sessions** — hierarchical parent ↔ child sessions with async coordination and auto-reports on completion.
|
|
40
82
|
|
|
41
|
-
|
|
83
|
+
## New in v0.2.1
|
|
42
84
|
|
|
43
|
-
- **
|
|
85
|
+
- 🎨 **Four UI themes** — dark, light, midnight, warm; synced server-side so every browser gets your pick.
|
|
86
|
+
- ⌨️ **TUI overhaul** — reworked input, verbose mode, and persistent history in the standalone terminal client.
|
|
87
|
+
- 🏙 **Halo City performance** — viewport culling + offscreen skyline; smooth on busy servers.
|
|
88
|
+
- 📊 **PPTX speaker-notes sidebar** — the slide preview now shows the notes lane alongside slides.
|
|
89
|
+
- ✂️ **Graceful interrupts, fully surfaced** — interrupted tool calls are repaired and shown in the session UI instead of vanishing.
|
|
90
|
+
|
|
91
|
+

|
|
92
|
+
|
|
93
|
+
## Quick Start
|
|
94
|
+
|
|
95
|
+
Published on npm as [`@turmind/halo`](https://www.npmjs.com/package/@turmind/halo) — one binary, all subcommands. After the three install commands above, open **http://localhost:9527**.
|
|
96
|
+
|
|
97
|
+
| Prerequisite | Notes |
|
|
98
|
+
|---|---|
|
|
99
|
+
| Node.js >= 22 | the only hard system requirement |
|
|
100
|
+
| An API key for any supported model provider | entered during `halo setup`; AWS Bedrock users can leave keys unset and use the standard credential chain (env / `~/.aws` / instance role) instead |
|
|
101
|
+
| pnpm >= 9 | source builds only |
|
|
102
|
+
|
|
103
|
+
- **Bind your provider to the agent**: `halo setup` stores keys; agents choose providers. The built-in `default` agent ships pointing at AWS Bedrock, so if you configured a different provider, switch it once in **Agents → default → model provider** — your first conversation will thank you.
|
|
104
|
+
- **Upgrade**: `halo upgrade && halo server restart`. The startup check refreshes bundled docs / agents / skills automatically when the on-disk template version is behind.
|
|
44
105
|
- **Docker / CI**: `halo setup --non-interactive` and supply credentials via the `HALO_PASSWORD` env var.
|
|
45
106
|
- **From source**: `pnpm install && pnpm build`.
|
|
46
107
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
108
|
+
### Talk to it from curl
|
|
109
|
+
|
|
110
|
+
Every workspace can expose a token-authenticated HTTP + SSE endpoint — the Web channel, aka the "build your own UI" channel:
|
|
111
|
+
|
|
112
|
+
1. In the admin, open **Channels → Web → Add Account**, pick a workspace and access level, and copy the token (shown once).
|
|
113
|
+
2. Stream a conversation:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
curl -N -H "x-token: $TOKEN" -H "Content-Type: application/json" \
|
|
117
|
+
-d '{"message":"What files are in this workspace?"}' \
|
|
118
|
+
http://localhost:9527/api/web/chat
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
The response is SSE frames — `session` / `thinking` / `tool_call` / `stream` / `complete` — full protocol in [`.halo/docs/guide/channels/web.md`](.halo/docs/guide/channels/web.md).
|
|
52
122
|
|
|
53
123
|
## Models
|
|
54
124
|
|
|
@@ -63,6 +133,7 @@ Configured per-agent through one provider-agnostic runtime. AWS Bedrock Claude i
|
|
|
63
133
|
| DeepSeek | |
|
|
64
134
|
| Kimi (Moonshot AI) | |
|
|
65
135
|
| MiniMax | |
|
|
136
|
+
| Mimo (Xiaomi) | Anthropic-compatible gateway, 1M context |
|
|
66
137
|
| Qwen (Aliyun) | |
|
|
67
138
|
| Hunyuan (Tencent) | |
|
|
68
139
|
| Doubao (Volcengine) | |
|
|
@@ -76,7 +147,7 @@ Every channel shares the same workspace and session state. Onboarding guides liv
|
|
|
76
147
|
| Channel | Transport | Notes |
|
|
77
148
|
|---|---|---|
|
|
78
149
|
| **Admin** | WebSocket | Full-featured browser UI |
|
|
79
|
-
| **Web** | HTTP + SSE | Token-authenticated API, independently deployable |
|
|
150
|
+
| **Web** | HTTP + SSE | Token-authenticated API, independently deployable — see [curl example](#talk-to-it-from-curl) |
|
|
80
151
|
| **CLI / TUI** | local | Standalone terminal client, embedded agent loop (no server required) |
|
|
81
152
|
| **Telegram** | Bot API | Long polling |
|
|
82
153
|
| **Slack** | Socket Mode | No public webhook required |
|
|
@@ -84,30 +155,21 @@ Every channel shares the same workspace and session state. Onboarding guides liv
|
|
|
84
155
|
| **WeChat** | QR bind | Scan to bind, mobile access |
|
|
85
156
|
| **ACP adapter** | stdio JSON-RPC | Bridges ACP clients (Claude Code, etc.) onto the Web channel |
|
|
86
157
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
<img src="assets/telegram-phone.jpg" alt="Halo in Telegram" width="270" />
|
|
91
|
-
</p>
|
|
92
|
-
<p align="center"><sub>Same workspace, driven from WeChat and Telegram on a phone.</sub></p>
|
|
93
|
-
|
|
94
|
-
## More Capabilities
|
|
158
|
+

|
|
159
|
+
<p align="center"><sub>The TUI runs the same agent loop in your terminal — here delegating to an executor and consolidating its report, no server needed.</sub></p>
|
|
95
160
|
|
|
96
|
-
|
|
97
|
-
- **Workspace tools** — `file_read` / `file_write` / `file_edit`, sandboxed `shell_exec`, `grep` / `glob`, `web_fetch`, `view_image`, plus session tools (`start_session`, `query_session`, `interrupt_session`, …) for multi-agent control.
|
|
98
|
-
- **Skills system** — Markdown-based skill definitions injected into agent prompts on demand; workspace-scoped or global, extensible without code changes.
|
|
99
|
-
- **Cron tasks** — scheduled agent runs (recurring or one-shot) that fan output out to bound channel accounts.
|
|
100
|
-
- **Halo City** — a read-only pixel **city block** that visualizes a server's runtime: each workspace is a building, each session an animal citizen at a desk, click anyone to inspect their live session log. Pure client-side canvas, zero model tokens. Lives at [`halo-city/`](halo-city/) — see [design notes](.halo/docs/design/halo-city.md).
|
|
161
|
+
## Halo City
|
|
101
162
|
|
|
102
|
-
|
|
163
|
+
A read-only pixel city that visualizes a live halo server: each workspace is a building, each session an animal citizen — at a desk when working, grabbing coffee or hitting the arcade when idle. Click any citizen to inspect the real thing: live session log, delegation chain, last tool call, token usage. Pure client-side canvas on a single polling endpoint — **zero model tokens burned**.
|
|
103
164
|
|
|
104
|
-

|
|
166
|
+
<p align="center"><sub>Street level: three sub-agent citizens heads-down in the <code>aurora-cafe</code> building; the inspector shows one executor's live log and delegation chain.</sub></p>
|
|
105
167
|
|
|
106
|
-
|
|
168
|
+
Lives at [`halo-city/`](halo-city/) (plain static files, no build) — see the [design notes](.halo/docs/design/halo-city.md).
|
|
107
169
|
|
|
108
170
|
## Tech Stack
|
|
109
171
|
|
|
110
|
-
- **Monorepo**: pnpm workspace (`
|
|
172
|
+
- **Monorepo**: pnpm workspace (`core`, `server`, `admin`, `cli`, `desktop`, `acp-adapter`, `web-demo`)
|
|
111
173
|
- **Backend**: Hono + WebSocket, single Node.js process on port 9527
|
|
112
174
|
- **Frontend**: Next.js 15 static export, served directly by Hono
|
|
113
175
|
- **Agent**: custom orchestration loop, provider-agnostic `ModelRuntime` interface
|
|
@@ -120,17 +182,18 @@ Every channel shares the same workspace and session state. Onboarding guides liv
|
|
|
120
182
|
- [`.halo/docs/requirements/overview.md`](.halo/docs/requirements/overview.md) — product concept
|
|
121
183
|
- [`.halo/docs/design/architecture.md`](.halo/docs/design/architecture.md) — backend architecture
|
|
122
184
|
- [`.halo/docs/design/evolution.md`](.halo/docs/design/evolution.md) — self-evolution design
|
|
185
|
+
- [`.halo/docs/guide/channels/`](.halo/docs/guide/channels/) — per-channel onboarding guides
|
|
123
186
|
- [`.halo/docs/dev/deploy.md`](.halo/docs/dev/deploy.md) — deployment (systemd / Nginx)
|
|
124
187
|
- [`.halo/docs/dev/env.md`](.halo/docs/dev/env.md) — env vars, build commands
|
|
125
188
|
- [`CLAUDE.md`](CLAUDE.md) — development instructions for Claude Code
|
|
126
189
|
|
|
127
190
|
## Status & Limitations
|
|
128
191
|
|
|
129
|
-
Halo is young
|
|
192
|
+
Halo is young — treat it as an early-stage project:
|
|
130
193
|
|
|
131
194
|
- **Sandbox isolates the filesystem, not the network.** The bubblewrap sandbox covers access levels and filesystem reach (host paths, `~/.aws`/`~/.ssh` masked), but does **not** isolate the network — code running inside it can still make outbound connections. The threat model is accidental damage and path escape by a trusted agent, **not** containment of a deliberately malicious skill exfiltrating data. Network isolation is on the roadmap.
|
|
132
|
-
- **
|
|
133
|
-
- **
|
|
195
|
+
- **Test coverage is unit/regression-level, not end-to-end.** 345 tests across the four packages (core, server, cli, admin) run on every push via CI, covering core logic — path-boundary checks, session repair, channel message formatting, the TUI engine, and more. There's no end-to-end or integration suite yet.
|
|
196
|
+
- **APIs and on-disk formats may still change between versions.** Expect rough edges while things stabilize.
|
|
134
197
|
|
|
135
198
|
If you hit something broken or surprising, please open an issue — early feedback is genuinely useful right now.
|
|
136
199
|
|
package/admin-out/404.html
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
<!DOCTYPE html><!--
|
|
1
|
+
<!DOCTYPE html><!--vHdygDsxwoyxkXg5umpZ1--><html lang="en" class="dark"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="preload" href="/_next/static/media/e4af272ccee01ff0-s.p.woff2" as="font" crossorigin="" type="font/woff2"/><link rel="stylesheet" href="/_next/static/css/66df341f99220f5c.css" data-precedence="next"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/webpack-47520cdc55be63e7.js"/><script src="/_next/static/chunks/fb4ec4d6-3fa44f69484f91b9.js" async=""></script><script src="/_next/static/chunks/635-3dd0043ed0520b9d.js" async=""></script><script src="/_next/static/chunks/main-app-483b436873410ddc.js" async=""></script><script src="/_next/static/chunks/212-170855bed19f67f3.js" async=""></script><script src="/_next/static/chunks/app/layout-c2fa8035998e48d5.js" async=""></script><meta name="robots" content="noindex"/><meta name="next-size-adjust" content=""/><title>404: This page could not be found.</title><title>Halo - Multi-Agent Workspace</title><meta name="description" content="Multi-agent collaboration workspace for complex project delivery"/><link rel="icon" href="/favicon.ico" type="image/x-icon" sizes="16x16"/><link rel="icon" href="/icon.svg?3a6863548daca964" type="image/svg+xml" sizes="any"/><script>try{var t=localStorage.getItem('halo_theme');if(t==='light'||t==='midnight'||t==='warm')document.documentElement.dataset.theme=t}catch(e){}</script><script src="/_next/static/chunks/polyfills-42372ed130431b0a.js" noModule=""></script></head><body class="__variable_f367f3 font-sans antialiased"><div hidden=""><!--$--><!--/$--></div><div style="font-family:system-ui,"Segoe UI",Roboto,Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji";height:100vh;text-align:center;display:flex;flex-direction:column;align-items:center;justify-content:center"><div><style>body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}</style><h1 class="next-error-h1" style="display:inline-block;margin:0 20px 0 0;padding:0 23px 0 0;font-size:24px;font-weight:500;vertical-align:top;line-height:49px">404</h1><div style="display:inline-block"><h2 style="font-size:14px;font-weight:400;line-height:49px;margin:0">This page could not be found.</h2></div></div></div><!--$--><!--/$--><script src="/_next/static/chunks/webpack-47520cdc55be63e7.js" id="_R_" async=""></script><script>(self.__next_f=self.__next_f||[]).push([0])</script><script>self.__next_f.push([1,"1:\"$Sreact.fragment\"\n2:I[59391,[\"212\",\"static/chunks/212-170855bed19f67f3.js\",\"177\",\"static/chunks/app/layout-c2fa8035998e48d5.js\"],\"ThemeProvider\"]\n3:I[26967,[\"212\",\"static/chunks/212-170855bed19f67f3.js\",\"177\",\"static/chunks/app/layout-c2fa8035998e48d5.js\"],\"AppI18nProvider\"]\n4:I[66048,[],\"\"]\n5:I[29926,[],\"\"]\n6:I[11789,[],\"OutletBoundary\"]\n8:I[21528,[],\"AsyncMetadataOutlet\"]\na:I[11789,[],\"ViewportBoundary\"]\nc:I[11789,[],\"MetadataBoundary\"]\nd:\"$Sreact.suspense\"\nf:I[79836,[],\"\"]\n:HL[\"/_next/static/media/e4af272ccee01ff0-s.p.woff2\",\"font\",{\"crossOrigin\":\"\",\"type\":\"font/woff2\"}]\n:HL[\"/_next/static/css/66df341f99220f5c.css\",\"style\"]\n"])</script><script>self.__next_f.push([1,"0:{\"P\":null,\"b\":\"vHdygDsxwoyxkXg5umpZ1\",\"p\":\"\",\"c\":[\"\",\"_not-found\"],\"i\":false,\"f\":[[[\"\",{\"children\":[\"/_not-found\",{\"children\":[\"__PAGE__\",{}]}]},\"$undefined\",\"$undefined\",true],[\"\",[\"$\",\"$1\",\"c\",{\"children\":[[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/css/66df341f99220f5c.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}]],[\"$\",\"html\",null,{\"lang\":\"en\",\"className\":\"dark\",\"suppressHydrationWarning\":true,\"children\":[[\"$\",\"head\",null,{\"children\":[\"$\",\"script\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"try{var t=localStorage.getItem('halo_theme');if(t==='light'||t==='midnight'||t==='warm')document.documentElement.dataset.theme=t}catch(e){}\"}}]}],[\"$\",\"body\",null,{\"className\":\"__variable_f367f3 font-sans antialiased\",\"children\":[\"$\",\"$L2\",null,{\"children\":[\"$\",\"$L3\",null,{\"children\":[\"$\",\"$L4\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L5\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]}]}]}]]}]]}],{\"children\":[\"/_not-found\",[\"$\",\"$1\",\"c\",{\"children\":[null,[\"$\",\"$L4\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L5\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]]}],{\"children\":[\"__PAGE__\",[\"$\",\"$1\",\"c\",{\"children\":[[[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}],[\"$\",\"div\",null,{\"style\":{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"textAlign\":\"center\",\"display\":\"flex\",\"flexDirection\":\"column\",\"alignItems\":\"center\",\"justifyContent\":\"center\"},\"children\":[\"$\",\"div\",null,{\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":{\"display\":\"inline-block\",\"margin\":\"0 20px 0 0\",\"padding\":\"0 23px 0 0\",\"fontSize\":24,\"fontWeight\":500,\"verticalAlign\":\"top\",\"lineHeight\":\"49px\"},\"children\":404}],[\"$\",\"div\",null,{\"style\":{\"display\":\"inline-block\"},\"children\":[\"$\",\"h2\",null,{\"style\":{\"fontSize\":14,\"fontWeight\":400,\"lineHeight\":\"49px\",\"margin\":0},\"children\":\"This page could not be found.\"}]}]]}]}]],null,[\"$\",\"$L6\",null,{\"children\":[\"$L7\",[\"$\",\"$L8\",null,{\"promise\":\"$@9\"}]]}]]}],{},null,false]},null,false]},null,false],[\"$\",\"$1\",\"h\",{\"children\":[[\"$\",\"meta\",null,{\"name\":\"robots\",\"content\":\"noindex\"}],[[\"$\",\"$La\",null,{\"children\":\"$Lb\"}],[\"$\",\"meta\",null,{\"name\":\"next-size-adjust\",\"content\":\"\"}]],[\"$\",\"$Lc\",null,{\"children\":[\"$\",\"div\",null,{\"hidden\":true,\"children\":[\"$\",\"$d\",null,{\"fallback\":null,\"children\":\"$Le\"}]}]}]]}],false]],\"m\":\"$undefined\",\"G\":[\"$f\",[]],\"s\":false,\"S\":true}\n"])</script><script>self.__next_f.push([1,"b:[[\"$\",\"meta\",\"0\",{\"charSet\":\"utf-8\"}],[\"$\",\"meta\",\"1\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}]]\n7:null\n"])</script><script>self.__next_f.push([1,"10:I[89592,[],\"IconMark\"]\n9:{\"metadata\":[[\"$\",\"title\",\"0\",{\"children\":\"Halo - Multi-Agent Workspace\"}],[\"$\",\"meta\",\"1\",{\"name\":\"description\",\"content\":\"Multi-agent collaboration workspace for complex project delivery\"}],[\"$\",\"link\",\"2\",{\"rel\":\"icon\",\"href\":\"/favicon.ico\",\"type\":\"image/x-icon\",\"sizes\":\"16x16\"}],[\"$\",\"link\",\"3\",{\"rel\":\"icon\",\"href\":\"/icon.svg?3a6863548daca964\",\"type\":\"image/svg+xml\",\"sizes\":\"any\"}],[\"$\",\"$L10\",\"4\",{}]],\"error\":null,\"digest\":\"$undefined\"}\n"])</script><script>self.__next_f.push([1,"e:\"$9:metadata\"\n"])</script></body></html>
|
package/admin-out/index.html
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
<!DOCTYPE html><!--
|
|
1
|
+
<!DOCTYPE html><!--vHdygDsxwoyxkXg5umpZ1--><html lang="en" class="dark"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="preload" href="/_next/static/media/e4af272ccee01ff0-s.p.woff2" as="font" crossorigin="" type="font/woff2"/><link rel="stylesheet" href="/_next/static/css/66df341f99220f5c.css" data-precedence="next"/><link rel="stylesheet" href="/_next/static/css/659eccb5db697b76.css" data-precedence="next"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/webpack-47520cdc55be63e7.js"/><script src="/_next/static/chunks/fb4ec4d6-3fa44f69484f91b9.js" async=""></script><script src="/_next/static/chunks/635-3dd0043ed0520b9d.js" async=""></script><script src="/_next/static/chunks/main-app-483b436873410ddc.js" async=""></script><script src="/_next/static/chunks/212-170855bed19f67f3.js" async=""></script><script src="/_next/static/chunks/app/layout-c2fa8035998e48d5.js" async=""></script><script src="/_next/static/chunks/1d2d5650-810a3ca1ae20cab5.js" async=""></script><script src="/_next/static/chunks/307-d7a99f9a4a436ec3.js" async=""></script><script src="/_next/static/chunks/app/page-31317ef1fb0ba31f.js" async=""></script><meta name="next-size-adjust" content=""/><title>Halo - Multi-Agent Workspace</title><meta name="description" content="Multi-agent collaboration workspace for complex project delivery"/><link rel="icon" href="/favicon.ico" type="image/x-icon" sizes="16x16"/><link rel="icon" href="/icon.svg?3a6863548daca964" type="image/svg+xml" sizes="any"/><script>try{var t=localStorage.getItem('halo_theme');if(t==='light'||t==='midnight'||t==='warm')document.documentElement.dataset.theme=t}catch(e){}</script><script src="/_next/static/chunks/polyfills-42372ed130431b0a.js" noModule=""></script></head><body class="__variable_f367f3 font-sans antialiased"><div hidden=""><!--$--><!--/$--></div><div class="flex h-screen w-screen items-center justify-center bg-[var(--background)]"><div class="text-sm text-[var(--muted-foreground)]">Loading...</div></div><!--$--><!--/$--><script src="/_next/static/chunks/webpack-47520cdc55be63e7.js" id="_R_" async=""></script><script>(self.__next_f=self.__next_f||[]).push([0])</script><script>self.__next_f.push([1,"1:\"$Sreact.fragment\"\n2:I[59391,[\"212\",\"static/chunks/212-170855bed19f67f3.js\",\"177\",\"static/chunks/app/layout-c2fa8035998e48d5.js\"],\"ThemeProvider\"]\n3:I[26967,[\"212\",\"static/chunks/212-170855bed19f67f3.js\",\"177\",\"static/chunks/app/layout-c2fa8035998e48d5.js\"],\"AppI18nProvider\"]\n4:I[66048,[],\"\"]\n5:I[29926,[],\"\"]\n6:I[57917,[],\"ClientPageRoot\"]\n7:I[11704,[\"560\",\"static/chunks/1d2d5650-810a3ca1ae20cab5.js\",\"307\",\"static/chunks/307-d7a99f9a4a436ec3.js\",\"212\",\"static/chunks/212-170855bed19f67f3.js\",\"974\",\"static/chunks/app/page-31317ef1fb0ba31f.js\"],\"default\"]\na:I[11789,[],\"OutletBoundary\"]\nc:I[21528,[],\"AsyncMetadataOutlet\"]\ne:I[11789,[],\"ViewportBoundary\"]\n10:I[11789,[],\"MetadataBoundary\"]\n11:\"$Sreact.suspense\"\n13:I[79836,[],\"\"]\n:HL[\"/_next/static/media/e4af272ccee01ff0-s.p.woff2\",\"font\",{\"crossOrigin\":\"\",\"type\":\"font/woff2\"}]\n:HL[\"/_next/static/css/66df341f99220f5c.css\",\"style\"]\n:HL[\"/_next/static/css/659eccb5db697b76.css\",\"style\"]\n"])</script><script>self.__next_f.push([1,"0:{\"P\":null,\"b\":\"vHdygDsxwoyxkXg5umpZ1\",\"p\":\"\",\"c\":[\"\",\"\"],\"i\":false,\"f\":[[[\"\",{\"children\":[\"__PAGE__\",{}]},\"$undefined\",\"$undefined\",true],[\"\",[\"$\",\"$1\",\"c\",{\"children\":[[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/css/66df341f99220f5c.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}]],[\"$\",\"html\",null,{\"lang\":\"en\",\"className\":\"dark\",\"suppressHydrationWarning\":true,\"children\":[[\"$\",\"head\",null,{\"children\":[\"$\",\"script\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"try{var t=localStorage.getItem('halo_theme');if(t==='light'||t==='midnight'||t==='warm')document.documentElement.dataset.theme=t}catch(e){}\"}}]}],[\"$\",\"body\",null,{\"className\":\"__variable_f367f3 font-sans antialiased\",\"children\":[\"$\",\"$L2\",null,{\"children\":[\"$\",\"$L3\",null,{\"children\":[\"$\",\"$L4\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L5\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":[[[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}],[\"$\",\"div\",null,{\"style\":{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"textAlign\":\"center\",\"display\":\"flex\",\"flexDirection\":\"column\",\"alignItems\":\"center\",\"justifyContent\":\"center\"},\"children\":[\"$\",\"div\",null,{\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":{\"display\":\"inline-block\",\"margin\":\"0 20px 0 0\",\"padding\":\"0 23px 0 0\",\"fontSize\":24,\"fontWeight\":500,\"verticalAlign\":\"top\",\"lineHeight\":\"49px\"},\"children\":404}],[\"$\",\"div\",null,{\"style\":{\"display\":\"inline-block\"},\"children\":[\"$\",\"h2\",null,{\"style\":{\"fontSize\":14,\"fontWeight\":400,\"lineHeight\":\"49px\",\"margin\":0},\"children\":\"This page could not be found.\"}]}]]}]}]],[]],\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]}]}]}]]}]]}],{\"children\":[\"__PAGE__\",[\"$\",\"$1\",\"c\",{\"children\":[[\"$\",\"$L6\",null,{\"Component\":\"$7\",\"searchParams\":{},\"params\":{},\"promises\":[\"$@8\",\"$@9\"]}],[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/css/659eccb5db697b76.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}]],[\"$\",\"$La\",null,{\"children\":[\"$Lb\",[\"$\",\"$Lc\",null,{\"promise\":\"$@d\"}]]}]]}],{},null,false]},null,false],[\"$\",\"$1\",\"h\",{\"children\":[null,[[\"$\",\"$Le\",null,{\"children\":\"$Lf\"}],[\"$\",\"meta\",null,{\"name\":\"next-size-adjust\",\"content\":\"\"}]],[\"$\",\"$L10\",null,{\"children\":[\"$\",\"div\",null,{\"hidden\":true,\"children\":[\"$\",\"$11\",null,{\"fallback\":null,\"children\":\"$L12\"}]}]}]]}],false]],\"m\":\"$undefined\",\"G\":[\"$13\",[]],\"s\":false,\"S\":true}\n"])</script><script>self.__next_f.push([1,"8:{}\n9:\"$0:f:0:1:2:children:1:props:children:0:props:params\"\n"])</script><script>self.__next_f.push([1,"f:[[\"$\",\"meta\",\"0\",{\"charSet\":\"utf-8\"}],[\"$\",\"meta\",\"1\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}]]\nb:null\n"])</script><script>self.__next_f.push([1,"14:I[89592,[],\"IconMark\"]\nd:{\"metadata\":[[\"$\",\"title\",\"0\",{\"children\":\"Halo - Multi-Agent Workspace\"}],[\"$\",\"meta\",\"1\",{\"name\":\"description\",\"content\":\"Multi-agent collaboration workspace for complex project delivery\"}],[\"$\",\"link\",\"2\",{\"rel\":\"icon\",\"href\":\"/favicon.ico\",\"type\":\"image/x-icon\",\"sizes\":\"16x16\"}],[\"$\",\"link\",\"3\",{\"rel\":\"icon\",\"href\":\"/icon.svg?3a6863548daca964\",\"type\":\"image/svg+xml\",\"sizes\":\"any\"}],[\"$\",\"$L14\",\"4\",{}]],\"error\":null,\"digest\":\"$undefined\"}\n"])</script><script>self.__next_f.push([1,"12:\"$d:metadata\"\n"])</script></body></html>
|
package/admin-out/index.txt
CHANGED
|
@@ -14,7 +14,7 @@ e:I[11789,[],"ViewportBoundary"]
|
|
|
14
14
|
:HL["/_next/static/media/e4af272ccee01ff0-s.p.woff2","font",{"crossOrigin":"","type":"font/woff2"}]
|
|
15
15
|
:HL["/_next/static/css/66df341f99220f5c.css","style"]
|
|
16
16
|
:HL["/_next/static/css/659eccb5db697b76.css","style"]
|
|
17
|
-
0:{"P":null,"b":"
|
|
17
|
+
0:{"P":null,"b":"vHdygDsxwoyxkXg5umpZ1","p":"","c":["",""],"i":false,"f":[[["",{"children":["__PAGE__",{}]},"$undefined","$undefined",true],["",["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/66df341f99220f5c.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]],["$","html",null,{"lang":"en","className":"dark","suppressHydrationWarning":true,"children":[["$","head",null,{"children":["$","script",null,{"dangerouslySetInnerHTML":{"__html":"try{var t=localStorage.getItem('halo_theme');if(t==='light'||t==='midnight'||t==='warm')document.documentElement.dataset.theme=t}catch(e){}"}}]}],["$","body",null,{"className":"__variable_f367f3 font-sans antialiased","children":["$","$L2",null,{"children":["$","$L3",null,{"children":["$","$L4",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],[]],"forbidden":"$undefined","unauthorized":"$undefined"}]}]}]}]]}]]}],{"children":["__PAGE__",["$","$1","c",{"children":[["$","$L6",null,{"Component":"$7","searchParams":{},"params":{},"promises":["$@8","$@9"]}],[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/659eccb5db697b76.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]],["$","$La",null,{"children":["$Lb",["$","$Lc",null,{"promise":"$@d"}]]}]]}],{},null,false]},null,false],["$","$1","h",{"children":[null,[["$","$Le",null,{"children":"$Lf"}],["$","meta",null,{"name":"next-size-adjust","content":""}]],["$","$L10",null,{"children":["$","div",null,{"hidden":true,"children":["$","$11",null,{"fallback":null,"children":"$L12"}]}]}]]}],false]],"m":"$undefined","G":["$13",[]],"s":false,"S":true}
|
|
18
18
|
8:{}
|
|
19
19
|
9:"$0:f:0:1:2:children:1:props:children:0:props:params"
|
|
20
20
|
f:[["$","meta","0",{"charSet":"utf-8"}],["$","meta","1",{"name":"viewport","content":"width=device-width, initial-scale=1"}]]
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# AgentCore Runtime Mode
|
|
2
|
+
|
|
3
|
+
Halo server as an **Amazon Bedrock AgentCore Runtime** container — a fourth
|
|
4
|
+
way to run halo (server / CLI / desktop / AgentCore). One env var flips it:
|
|
5
|
+
`HALO_RUNTIME_MODE=agentcore`. Demo package: `packages/agentcore-demo/`
|
|
6
|
+
(Dockerfile, chat frontend, CDK stack, auth Lambdas — its README carries the
|
|
7
|
+
operational gotchas; this doc covers how the mode works inside the server).
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
Browser (static frontend, S3 + CloudFront)
|
|
11
|
+
│ /api/login, /api/verify → CloudFront /api/* behavior → API GW → auth Lambda (DDB users, JWT)
|
|
12
|
+
│ /api/ws-presign → presign Lambda (SigV4-signs the AgentCore WS URL)
|
|
13
|
+
│ wss (presigned URL, 5-min TTL)
|
|
14
|
+
▼
|
|
15
|
+
AgentCore Runtime (per-session microVM, auth terminated here)
|
|
16
|
+
│ X-Amzn-Bedrock-AgentCore-Runtime-Session-Id = user UUID
|
|
17
|
+
▼
|
|
18
|
+
halo server :8080 (HALO_RUNTIME_MODE=agentcore)
|
|
19
|
+
├── GET /ping Healthy | HealthyBusy (any running agent session)
|
|
20
|
+
├── POST /invocations {"input":{"prompt"}} → full assistant message
|
|
21
|
+
└── WS /ws streaming frames (primary path)
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## What the mode changes (packages/server/src/index.ts)
|
|
25
|
+
|
|
26
|
+
`config.server.runtimeMode === 'agentcore'` (env `HALO_RUNTIME_MODE`) skips:
|
|
27
|
+
|
|
28
|
+
- **Password/JWT gate** — AgentCore terminates auth upstream (SigV4 presign /
|
|
29
|
+
OAuth); the container is only reachable through the runtime.
|
|
30
|
+
- **Single-instance lock** — one microVM per session; many server processes
|
|
31
|
+
coexist by design.
|
|
32
|
+
- **Channels, cron, evolution, archive daemon** — meaningless in an ephemeral
|
|
33
|
+
per-session microVM; sessions are driven only through the AgentCore surface.
|
|
34
|
+
|
|
35
|
+
Everything else (agent loop, tools, skills, sqlite persistence) is the normal
|
|
36
|
+
server. The adapter itself is `packages/server/src/routes/agentcore.ts`,
|
|
37
|
+
mounted at the root (the AgentCore contract paths live outside `/api`).
|
|
38
|
+
|
|
39
|
+
## Per-user workspace isolation
|
|
40
|
+
|
|
41
|
+
`userWorkspace(base, runtimeSessionId)` maps each runtime session id to
|
|
42
|
+
`<HALO_WORKSPACE>/users/<sanitized-id>/` — an isolated workspace with its own
|
|
43
|
+
`.halo/` (sqlite + session files). The id chain:
|
|
44
|
+
|
|
45
|
+
DDB `agentcore-demo-users` UUID → login response → frontend uses it as
|
|
46
|
+
sessionId → presign Lambda signs it into
|
|
47
|
+
`X-Amzn-Bedrock-AgentCore-Runtime-Session-Id` → adapter routes the workspace.
|
|
48
|
+
|
|
49
|
+
So **1 user = 1 runtime session id = 1 workspace**: users never see each
|
|
50
|
+
other's history; reconnecting with the same id resumes the same conversation.
|
|
51
|
+
`HALO_WORKSPACE` points at an EFS mount (`/mnt/efs`) — microVMs are ephemeral,
|
|
52
|
+
EFS makes the workspaces survive session termination and image rollouts.
|
|
53
|
+
|
|
54
|
+
## WS protocol quirks (why /init exists)
|
|
55
|
+
|
|
56
|
+
The AgentCore WS proxy only forwards **client frames containing `inputText`**
|
|
57
|
+
and cannot push server frames on connect. Hence:
|
|
58
|
+
|
|
59
|
+
- Frontend sends `{"inputText":"/init"}` after open; the server special-cases
|
|
60
|
+
it (also accepts `{"type":"init"}`) and replies with a `history` frame —
|
|
61
|
+
a full snapshot, which the frontend renders by rebuild-from-scratch (not
|
|
62
|
+
append), keyed by a signature so identical snapshots skip re-rendering.
|
|
63
|
+
- Frames without `inputText` are silently ignored server-side — the frontend
|
|
64
|
+
uses `{type:'ping'}` every 30s purely to keep the proxy from cutting the
|
|
65
|
+
socket.
|
|
66
|
+
- `/session switch` sends a `{type:'switch'}` frame → frontend clears, then
|
|
67
|
+
the follow-up history frame rebuilds.
|
|
68
|
+
|
|
69
|
+
## Session lifecycle (the part everyone gets wrong)
|
|
70
|
+
|
|
71
|
+
- Idle timeout (`idleRuntimeSessionTimeout`) terminates a session whose
|
|
72
|
+
`/ping` reports `Healthy`; `maxLifetime` (8h) force-terminates even busy
|
|
73
|
+
ones; failed health checks kill immediately.
|
|
74
|
+
- **An open WebSocket = an in-flight invocation** — the session never counts
|
|
75
|
+
as idle while a socket is open. The 30s frontend keepalive therefore keeps
|
|
76
|
+
the whole session warm; effective idle timeout ≈ "after the tab closes".
|
|
77
|
+
- `/ping` returns `HealthyBusy` whenever any agent session is running
|
|
78
|
+
(`registry.list().some(sm => sm.hasRunningSessions())`) — the official
|
|
79
|
+
keep-alive for long tool chains with no open connection.
|
|
80
|
+
- Termination is cheap: data is on EFS, next connect cold-starts (~3s) and
|
|
81
|
+
history reloads. `stop-runtime-session` kills one session on demand; there
|
|
82
|
+
is **no list/get-runtime-sessions API** (observe via CloudWatch `Sessions`
|
|
83
|
+
metric + runtime log filtering).
|
|
84
|
+
|
|
85
|
+
## Ops crib sheet
|
|
86
|
+
|
|
87
|
+
- CloudWatch logs capture container **stdout**; halo's logger drops
|
|
88
|
+
sub-threshold lines before stdout — set `HALO_LOG_LEVEL=info` or the log
|
|
89
|
+
group stays near-empty.
|
|
90
|
+
- `update-agent-runtime` **replaces the whole config** — omit
|
|
91
|
+
`--filesystem-configurations` and the EFS mount silently disappears.
|
|
92
|
+
Fetch-modify-send, and strip `requireServiceS3Endpoint` (rejected on
|
|
93
|
+
newer runtimes).
|
|
94
|
+
- VPC mode has no public IP: private subnets need `0.0.0.0/0 → NAT` or all
|
|
95
|
+
egress (Bedrock included) hangs → opaque 502s.
|
|
96
|
+
- Full operational detail + deploy walkthrough:
|
|
97
|
+
`packages/agentcore-demo/README.md`.
|
|
@@ -109,7 +109,7 @@ Sandbox is whitelist-cp from main workspace (only: `INSTRUCTIONS.md`, `INDEX.md`
|
|
|
109
109
|
### Phase B — Dry-run + Fix Loop
|
|
110
110
|
|
|
111
111
|
```
|
|
112
|
-
timeout
|
|
112
|
+
timeout 1800 halo cli -a <patch.testScenario.agentId> -n -w <runDir>/sandbox \
|
|
113
113
|
--access workspace <patch.testScenario.testMessage>
|
|
114
114
|
```
|
|
115
115
|
|
|
@@ -174,7 +174,7 @@ The wrapper clears any stale ABORT.md (from a crashed previous attempt) at the s
|
|
|
174
174
|
For each source_run_id:
|
|
175
175
|
|
|
176
176
|
1. Read `testScenario` from source run's `patch.md`.
|
|
177
|
-
2. Run `timeout
|
|
177
|
+
2. Run `timeout 1800 halo cli -a <agentId> -n -w <applyDir>/sandbox <testMessage>` against merged sandbox.
|
|
178
178
|
3. Spawn `__score__` with regress-mode brief, write `regress/<runId>/score.json`.
|
|
179
179
|
4. Any score with `lint < 50` or `behavior < 50` → regression, abort with `failed`.
|
|
180
180
|
|
|
@@ -34,10 +34,11 @@ Halo 服务器运行态的**街景式**像素可视化:侧视、剖面的像素
|
|
|
34
34
|
| 🪜 楼梯间 | 大楼左侧,真的逐层爬上爬下(没有传送) |
|
|
35
35
|
| 💺 工作层 | 每层 3 张工位(按 agent 名固定)+ 1 个技能站 + 随机小设施(盆栽/小书架/白板/售货机);干活时屏幕滚代码 |
|
|
36
36
|
| 🍵 公共层 | 冰箱(偶尔开门漏光)、水吧(水壶冒汽)、书报架、沙发,外加街机/鱼缸/猫爬架三选一;右侧伸出**阳台**(烟灰桶+盆栽)——抽烟点 |
|
|
37
|
-
| 🚬 习惯 | 每个 session 由 id hash 派生 **3 个固定偏好**(
|
|
38
|
-
| 🧭 就近原则 | 市民**生在自己的归属层**(
|
|
37
|
+
| 🚬 习惯 | 每个 session 由 id hash 派生 **3 个固定偏好**(抽烟/咖啡/泡茶/翻冰箱/看书/街机/看鱼/撸猫/打电话/下楼遛弯/沙发/工位打游戏/工位刷手机),摸鱼时偏好权重 ~4×——"这个会话就爱在阳台抽烟"是稳定人设,不是随机骰子(工位打游戏/工位刷手机不挪窝,就在自己座位上摸鱼;面板文案里"工位刷手机"沿用了"打电话"那条文案) |
|
|
38
|
+
| 🧭 就近原则 | 市民**生在自己的归属层**(自己的工位层;子代理不论嵌套多深都解析到所在会话树的**根会话**工位层,不再掉进大堂)。休息活动以**归属层**为锚点找最近的公共层,不会为了倒杯茶爬通天,**也不会随时间往低层漂**——12 楼的人永远回 F11 休息,不会一路沉到大堂。街机/鱼缸/猫爬架这类稀有设施只在归属层 **±4 层**的漫游带内找最近一个,带外直接放弃改走最近的休息层;`下楼遛弯` 同样按漫游带算——归属层在 F3 及以下才真下街,F4+ 改在带内最近的休息层放风 |
|
|
39
|
+
| 📌 稳定工位 | 每个**根会话**的工位楼层只在**第一次出现**时分配一次(选最低空位),离开释放、回来复用——不会因为 `/api/show/state` 按 `updated_at DESC` 排序每次轮询都重排,否则摸鱼回来就会撞上"工位换人"的错觉 |
|
|
39
40
|
| 💡 灯光 | 有人在的楼层灯亮(running 或 idle 都算——摸鱼也开灯),只有彻底 stopped 的层才熄;天黑后街灯/霓虹/远景窗火全亮 |
|
|
40
|
-
| ↳ 小一号 |
|
|
41
|
+
| ↳ 小一号 | 子代理:生在所在会话树的**根会话**工位层(而不是直接父代理那层),干活时聚在**直接**父代理桌边,不占工位 |
|
|
41
42
|
|
|
42
43
|
进出有戏:新会话直接出现在自己的工位层(从本层楼梯口走到工位,不再从街上爬通天);结束的走出门沿街远去淡出。
|
|
43
44
|
|
|
@@ -51,7 +52,8 @@ Halo 服务器运行态的**街景式**像素可视化:侧视、剖面的像素
|
|
|
51
52
|
- **上下文仪表**:`134k / 200k (67%)` —— 分母是该会话的**真实** `maxContextTokens`
|
|
52
53
|
- **委派链**:父/子会话可点击跳转,每行带 token 数和消息数
|
|
53
54
|
- **点楼层**:该层的会话委派关系树(缩进、可点跳转)——工作层看"谁在这层干活、
|
|
54
|
-
带着哪些子代理",公共层看"谁在摸鱼"
|
|
55
|
+
带着哪些子代理",公共层看"谁在摸鱼";**工位在这层的人即使正外出休息也照样算在这层**
|
|
56
|
+
(按归属工位层统计,不是按人此刻站在哪),点楼层永远能看全常驻名单
|
|
55
57
|
- 点大楼:全员 roster + token 合计;点技能站:谁在用
|
|
56
58
|
|
|
57
59
|
## 街景与载具
|
|
@@ -77,6 +79,9 @@ Halo 服务器运行态的**街景式**像素可视化:侧视、剖面的像素
|
|
|
77
79
|
- **纯净模式(zen)**:淡出所有 HUD(统计/动态/图例/缩放条/面板),只留街景,适合大屏常驻展示
|
|
78
80
|
- **多语言(i18n)**:中文 / English 一键切;`?lang=en`/`?lang=zh` 直达,选择存 localStorage。
|
|
79
81
|
运行时文案走 `t()`,静态 DOM 走 `data-i18n` 属性填充
|
|
82
|
+
- **背景音乐**:🎵/🔇 HUD 按钮(挨着 中/EN),纯 Web Audio 程序生成、零素材,
|
|
83
|
+
默认开、偏好存 localStorage;受浏览器自动播放策略限制,AudioContext 在首次
|
|
84
|
+
用户手势后才创建,关掉时真正 suspend(零 CPU),音频图与画面 rAF 循环完全独立
|
|
80
85
|
|
|
81
86
|
## 调试参数
|
|
82
87
|
|
|
@@ -107,10 +112,18 @@ js/
|
|
|
107
112
|
## 服务端配套
|
|
108
113
|
|
|
109
114
|
- `GET /api/show/session?ws=&id=` — 只读会话详情:裁剪后的消息日志 + 真实
|
|
110
|
-
token 上限。鉴权同 `/api/show/state`(x-token
|
|
115
|
+
token 上限。鉴权同 `/api/show/state`(x-token;`full`/`observer` 可跨
|
|
116
|
+
workspace 读取,其余 accessLevel 只能看自己 workspace)
|
|
111
117
|
- `/api/show/state` — 无活跃 UIState 的会话(idle/stopped/重启后)token
|
|
112
118
|
从会话文件头读取(mtime 缓存,不随轮询刷盘),不显示 0;含 `messageCount` 字段
|
|
113
119
|
|
|
120
|
+
> **`observer` token 的权限面**:除了 `/show/state` 的聚合计数外,`observer`
|
|
121
|
+
> 还能调 `/show/session` 读取**任意 workspace** 任意会话的明细——最近 40 条
|
|
122
|
+
> 消息(每条截断到 600 字,tool input 截到 200 字)。它是"看板/监控"用的
|
|
123
|
+
> 全局只读角色,但这条 transcript 读取能力不止是计数;签发 observer token 时
|
|
124
|
+
> 要知道它相当于给了跨 workspace 的会话内容只读权限,不要把它当成纯粹的
|
|
125
|
+
> "数字仪表盘"凭证随手发放。
|
|
126
|
+
|
|
114
127
|
## 性能设计
|
|
115
128
|
|
|
116
129
|
原则:一个纯只读可视化页面,轮询**不得对服务端会话生命周期产生任何副作用**,
|
|
@@ -296,8 +296,8 @@ general: # built-in declarer (the server itself
|
|
|
296
296
|
max_message_slice: 800
|
|
297
297
|
summarize_timeout_sec: 300
|
|
298
298
|
sandbox:
|
|
299
|
-
hidden_dirs: "~/.halo/secrets,~/.aws,~/.ssh,~/.gnupg,~/.docker"
|
|
300
|
-
hidden_files: "~/.npmrc,~/.bash_history,~/.gitconfig"
|
|
299
|
+
hidden_dirs: "~/.halo/secrets,~/.aws,~/.ssh,~/.gnupg,~/.docker,~/.config/gh"
|
|
300
|
+
hidden_files: "~/.npmrc,~/.bash_history,~/.gitconfig,~/.git-credentials,~/.netrc"
|
|
301
301
|
logging:
|
|
302
302
|
level: warn
|
|
303
303
|
|
|
@@ -352,8 +352,8 @@ A value of the form `<<ENV_NAME>>` is replaced at read time with `process.env.EN
|
|
|
352
352
|
| `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` |
|
|
353
353
|
| `general.limits.ws_event_buffer` | 5000 | Events buffered per detached WS session before oldest are dropped on reattach |
|
|
354
354
|
| `general.limits.terminal_scrollback_bytes` | 50000 | Off-screen scrollback bytes retained per detached persistent terminal |
|
|
355
|
-
| `general.sandbox.hidden_dirs` | `~/.halo/secrets,~/.aws,~/.ssh,~/.gnupg,~/.docker` | bwrap tmpfs overlay (Linux only) |
|
|
356
|
-
| `general.sandbox.hidden_files` | `~/.npmrc,~/.bash_history,~/.gitconfig` | bwrap /dev/null bind (Linux only) |
|
|
355
|
+
| `general.sandbox.hidden_dirs` | `~/.halo/secrets,~/.aws,~/.ssh,~/.gnupg,~/.docker,~/.config/gh` | bwrap tmpfs overlay (Linux only) |
|
|
356
|
+
| `general.sandbox.hidden_files` | `~/.npmrc,~/.bash_history,~/.gitconfig,~/.git-credentials,~/.netrc` | bwrap /dev/null bind (Linux only) |
|
|
357
357
|
| `general.logging.level` | warn | `debug` / `info` / `warn` / `error` |
|
|
358
358
|
|
|
359
359
|
Schema source: [packages/server/src/settings-schema.ts](../../../packages/server/src/settings-schema.ts) `generalSection()`.
|