mach6-core 1.1.0
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 +454 -0
- package/dist/agent/context-monitor.d.ts +40 -0
- package/dist/agent/context-monitor.d.ts.map +1 -0
- package/dist/agent/context-monitor.js +138 -0
- package/dist/agent/context-monitor.js.map +1 -0
- package/dist/agent/context.d.ts +8 -0
- package/dist/agent/context.d.ts.map +1 -0
- package/dist/agent/context.js +197 -0
- package/dist/agent/context.js.map +1 -0
- package/dist/agent/runner.d.ts +42 -0
- package/dist/agent/runner.d.ts.map +1 -0
- package/dist/agent/runner.js +168 -0
- package/dist/agent/runner.js.map +1 -0
- package/dist/agent/system-prompt.d.ts +10 -0
- package/dist/agent/system-prompt.d.ts.map +1 -0
- package/dist/agent/system-prompt.js +120 -0
- package/dist/agent/system-prompt.js.map +1 -0
- package/dist/boot/sequence.d.ts +34 -0
- package/dist/boot/sequence.d.ts.map +1 -0
- package/dist/boot/sequence.js +103 -0
- package/dist/boot/sequence.js.map +1 -0
- package/dist/channels/__test__/integration.test.d.ts +8 -0
- package/dist/channels/__test__/integration.test.d.ts.map +1 -0
- package/dist/channels/__test__/integration.test.js +221 -0
- package/dist/channels/__test__/integration.test.js.map +1 -0
- package/dist/channels/adapter.d.ts +53 -0
- package/dist/channels/adapter.d.ts.map +1 -0
- package/dist/channels/adapter.js +164 -0
- package/dist/channels/adapter.js.map +1 -0
- package/dist/channels/adapters/discord.d.ts +49 -0
- package/dist/channels/adapters/discord.d.ts.map +1 -0
- package/dist/channels/adapters/discord.js +382 -0
- package/dist/channels/adapters/discord.js.map +1 -0
- package/dist/channels/adapters/whatsapp.d.ts +59 -0
- package/dist/channels/adapters/whatsapp.d.ts.map +1 -0
- package/dist/channels/adapters/whatsapp.js +503 -0
- package/dist/channels/adapters/whatsapp.js.map +1 -0
- package/dist/channels/bus.d.ts +55 -0
- package/dist/channels/bus.d.ts.map +1 -0
- package/dist/channels/bus.js +307 -0
- package/dist/channels/bus.js.map +1 -0
- package/dist/channels/formatter.d.ts +16 -0
- package/dist/channels/formatter.d.ts.map +1 -0
- package/dist/channels/formatter.js +226 -0
- package/dist/channels/formatter.js.map +1 -0
- package/dist/channels/presence.d.ts +67 -0
- package/dist/channels/presence.d.ts.map +1 -0
- package/dist/channels/presence.js +209 -0
- package/dist/channels/presence.js.map +1 -0
- package/dist/channels/registry.d.ts +57 -0
- package/dist/channels/registry.d.ts.map +1 -0
- package/dist/channels/registry.js +159 -0
- package/dist/channels/registry.js.map +1 -0
- package/dist/channels/router.d.ts +49 -0
- package/dist/channels/router.d.ts.map +1 -0
- package/dist/channels/router.js +244 -0
- package/dist/channels/router.js.map +1 -0
- package/dist/channels/types.d.ts +279 -0
- package/dist/channels/types.d.ts.map +1 -0
- package/dist/channels/types.js +67 -0
- package/dist/channels/types.js.map +1 -0
- package/dist/cli/brand.d.ts +71 -0
- package/dist/cli/brand.d.ts.map +1 -0
- package/dist/cli/brand.js +194 -0
- package/dist/cli/brand.js.map +1 -0
- package/dist/cli/wizard.d.ts +8 -0
- package/dist/cli/wizard.d.ts.map +1 -0
- package/dist/cli/wizard.js +520 -0
- package/dist/cli/wizard.js.map +1 -0
- package/dist/config/config.d.ts +47 -0
- package/dist/config/config.d.ts.map +1 -0
- package/dist/config/config.js +63 -0
- package/dist/config/config.js.map +1 -0
- package/dist/config/validator.d.ts +18 -0
- package/dist/config/validator.d.ts.map +1 -0
- package/dist/config/validator.js +92 -0
- package/dist/config/validator.js.map +1 -0
- package/dist/cron/budget.d.ts +39 -0
- package/dist/cron/budget.d.ts.map +1 -0
- package/dist/cron/budget.js +98 -0
- package/dist/cron/budget.js.map +1 -0
- package/dist/formatters/markdown.d.ts +6 -0
- package/dist/formatters/markdown.d.ts.map +1 -0
- package/dist/formatters/markdown.js +85 -0
- package/dist/formatters/markdown.js.map +1 -0
- package/dist/gateway/daemon.d.ts +97 -0
- package/dist/gateway/daemon.d.ts.map +1 -0
- package/dist/gateway/daemon.js +772 -0
- package/dist/gateway/daemon.js.map +1 -0
- package/dist/heartbeat/scheduler.d.ts +45 -0
- package/dist/heartbeat/scheduler.d.ts.map +1 -0
- package/dist/heartbeat/scheduler.js +102 -0
- package/dist/heartbeat/scheduler.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +305 -0
- package/dist/index.js.map +1 -0
- package/dist/memory/integrity.d.ts +37 -0
- package/dist/memory/integrity.d.ts.map +1 -0
- package/dist/memory/integrity.js +108 -0
- package/dist/memory/integrity.js.map +1 -0
- package/dist/providers/anthropic.d.ts +3 -0
- package/dist/providers/anthropic.d.ts.map +1 -0
- package/dist/providers/anthropic.js +232 -0
- package/dist/providers/anthropic.js.map +1 -0
- package/dist/providers/diagnostics.d.ts +18 -0
- package/dist/providers/diagnostics.d.ts.map +1 -0
- package/dist/providers/diagnostics.js +87 -0
- package/dist/providers/diagnostics.js.map +1 -0
- package/dist/providers/github-copilot.d.ts +3 -0
- package/dist/providers/github-copilot.d.ts.map +1 -0
- package/dist/providers/github-copilot.js +145 -0
- package/dist/providers/github-copilot.js.map +1 -0
- package/dist/providers/gladius.d.ts +3 -0
- package/dist/providers/gladius.d.ts.map +1 -0
- package/dist/providers/gladius.js +16 -0
- package/dist/providers/gladius.js.map +1 -0
- package/dist/providers/openai.d.ts +3 -0
- package/dist/providers/openai.d.ts.map +1 -0
- package/dist/providers/openai.js +161 -0
- package/dist/providers/openai.js.map +1 -0
- package/dist/providers/retry.d.ts +2 -0
- package/dist/providers/retry.d.ts.map +1 -0
- package/dist/providers/retry.js +50 -0
- package/dist/providers/retry.js.map +1 -0
- package/dist/providers/types.d.ts +78 -0
- package/dist/providers/types.d.ts.map +1 -0
- package/dist/providers/types.js +3 -0
- package/dist/providers/types.js.map +1 -0
- package/dist/security/sanitizer.d.ts +26 -0
- package/dist/security/sanitizer.d.ts.map +1 -0
- package/dist/security/sanitizer.js +115 -0
- package/dist/security/sanitizer.js.map +1 -0
- package/dist/sessions/manager.d.ts +40 -0
- package/dist/sessions/manager.d.ts.map +1 -0
- package/dist/sessions/manager.js +255 -0
- package/dist/sessions/manager.js.map +1 -0
- package/dist/sessions/queue.d.ts +41 -0
- package/dist/sessions/queue.d.ts.map +1 -0
- package/dist/sessions/queue.js +93 -0
- package/dist/sessions/queue.js.map +1 -0
- package/dist/sessions/store.d.ts +12 -0
- package/dist/sessions/store.d.ts.map +1 -0
- package/dist/sessions/store.js +74 -0
- package/dist/sessions/store.js.map +1 -0
- package/dist/sessions/sub-agent.d.ts +18 -0
- package/dist/sessions/sub-agent.d.ts.map +1 -0
- package/dist/sessions/sub-agent.js +117 -0
- package/dist/sessions/sub-agent.js.map +1 -0
- package/dist/sessions/types.d.ts +48 -0
- package/dist/sessions/types.d.ts.map +1 -0
- package/dist/sessions/types.js +3 -0
- package/dist/sessions/types.js.map +1 -0
- package/dist/test/channel-integration.d.ts +10 -0
- package/dist/test/channel-integration.d.ts.map +1 -0
- package/dist/test/channel-integration.js +226 -0
- package/dist/test/channel-integration.js.map +1 -0
- package/dist/test/prompt-test.d.ts +2 -0
- package/dist/test/prompt-test.d.ts.map +1 -0
- package/dist/test/prompt-test.js +33 -0
- package/dist/test/prompt-test.js.map +1 -0
- package/dist/test/smoke.d.ts +8 -0
- package/dist/test/smoke.d.ts.map +1 -0
- package/dist/test/smoke.js +134 -0
- package/dist/test/smoke.js.map +1 -0
- package/dist/tools/builtin/comb.d.ts +4 -0
- package/dist/tools/builtin/comb.d.ts.map +1 -0
- package/dist/tools/builtin/comb.js +50 -0
- package/dist/tools/builtin/comb.js.map +1 -0
- package/dist/tools/builtin/edit.d.ts +3 -0
- package/dist/tools/builtin/edit.d.ts.map +1 -0
- package/dist/tools/builtin/edit.js +42 -0
- package/dist/tools/builtin/edit.js.map +1 -0
- package/dist/tools/builtin/exec.d.ts +3 -0
- package/dist/tools/builtin/exec.d.ts.map +1 -0
- package/dist/tools/builtin/exec.js +75 -0
- package/dist/tools/builtin/exec.js.map +1 -0
- package/dist/tools/builtin/image.d.ts +3 -0
- package/dist/tools/builtin/image.d.ts.map +1 -0
- package/dist/tools/builtin/image.js +208 -0
- package/dist/tools/builtin/image.js.map +1 -0
- package/dist/tools/builtin/memory.d.ts +3 -0
- package/dist/tools/builtin/memory.d.ts.map +1 -0
- package/dist/tools/builtin/memory.js +36 -0
- package/dist/tools/builtin/memory.js.map +1 -0
- package/dist/tools/builtin/message.d.ts +13 -0
- package/dist/tools/builtin/message.d.ts.map +1 -0
- package/dist/tools/builtin/message.js +330 -0
- package/dist/tools/builtin/message.js.map +1 -0
- package/dist/tools/builtin/process.d.ts +43 -0
- package/dist/tools/builtin/process.d.ts.map +1 -0
- package/dist/tools/builtin/process.js +178 -0
- package/dist/tools/builtin/process.js.map +1 -0
- package/dist/tools/builtin/read.d.ts +3 -0
- package/dist/tools/builtin/read.d.ts.map +1 -0
- package/dist/tools/builtin/read.js +36 -0
- package/dist/tools/builtin/read.js.map +1 -0
- package/dist/tools/builtin/spawn.d.ts +8 -0
- package/dist/tools/builtin/spawn.d.ts.map +1 -0
- package/dist/tools/builtin/spawn.js +90 -0
- package/dist/tools/builtin/spawn.js.map +1 -0
- package/dist/tools/builtin/tts.d.ts +3 -0
- package/dist/tools/builtin/tts.d.ts.map +1 -0
- package/dist/tools/builtin/tts.js +77 -0
- package/dist/tools/builtin/tts.js.map +1 -0
- package/dist/tools/builtin/web-fetch.d.ts +3 -0
- package/dist/tools/builtin/web-fetch.d.ts.map +1 -0
- package/dist/tools/builtin/web-fetch.js +46 -0
- package/dist/tools/builtin/web-fetch.js.map +1 -0
- package/dist/tools/builtin/write.d.ts +3 -0
- package/dist/tools/builtin/write.d.ts.map +1 -0
- package/dist/tools/builtin/write.js +31 -0
- package/dist/tools/builtin/write.js.map +1 -0
- package/dist/tools/mcp-bridge.d.ts +42 -0
- package/dist/tools/mcp-bridge.d.ts.map +1 -0
- package/dist/tools/mcp-bridge.js +198 -0
- package/dist/tools/mcp-bridge.js.map +1 -0
- package/dist/tools/policy.d.ts +57 -0
- package/dist/tools/policy.d.ts.map +1 -0
- package/dist/tools/policy.js +106 -0
- package/dist/tools/policy.js.map +1 -0
- package/dist/tools/registry.d.ts +15 -0
- package/dist/tools/registry.d.ts.map +1 -0
- package/dist/tools/registry.js +41 -0
- package/dist/tools/registry.js.map +1 -0
- package/dist/tools/sandbox.d.ts +91 -0
- package/dist/tools/sandbox.d.ts.map +1 -0
- package/dist/tools/sandbox.js +279 -0
- package/dist/tools/sandbox.js.map +1 -0
- package/dist/tools/types.d.ts +23 -0
- package/dist/tools/types.d.ts.map +1 -0
- package/dist/tools/types.js +3 -0
- package/dist/tools/types.js.map +1 -0
- package/dist/web/http-api.d.ts +61 -0
- package/dist/web/http-api.d.ts.map +1 -0
- package/dist/web/http-api.js +200 -0
- package/dist/web/http-api.js.map +1 -0
- package/dist/web/server.d.ts +7 -0
- package/dist/web/server.d.ts.map +1 -0
- package/dist/web/server.js +396 -0
- package/dist/web/server.js.map +1 -0
- package/mach6.example.json +50 -0
- package/package.json +58 -0
- package/web/index.html +1370 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Artifact Virtual (SMC-Private) Limited
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,454 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
# ⚡ Mach6
|
|
4
|
+
|
|
5
|
+
**Multi-channel AI agent framework that runs on a laptop.**
|
|
6
|
+
|
|
7
|
+
[](LICENSE)
|
|
8
|
+
[](https://nodejs.org/)
|
|
9
|
+
[]()
|
|
10
|
+
[](https://www.typescriptlang.org/)
|
|
11
|
+
|
|
12
|
+
A persistent daemon that connects to messaging platforms, routes conversations through LLM providers, and executes tool calls in an agentic loop. No cloud dependencies. No vendor lock-in. **Your machine, your data, your keys.**
|
|
13
|
+
|
|
14
|
+
[Quick Start](#-quick-start) · [Architecture](#-architecture) · [Config](#-configuration) · [Providers](#-providers) · [Tools](#-tools) · [Web UI](#-web-ui)
|
|
15
|
+
|
|
16
|
+
</div>
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## 🚀 Quick Start
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
# Clone & build
|
|
24
|
+
git clone https://github.com/amuzetnoM/mach6.git
|
|
25
|
+
cd mach6
|
|
26
|
+
npm install && npm run build
|
|
27
|
+
|
|
28
|
+
# Interactive setup — generates mach6.json + .env
|
|
29
|
+
npx mach6 init
|
|
30
|
+
|
|
31
|
+
# Start the daemon
|
|
32
|
+
node dist/gateway/daemon.js --config=mach6.json
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
> **Windows (PowerShell):** Same commands — Mach6 is fully cross-platform. Use `.\mach6.ps1` or `node dist/gateway/daemon.js --config=mach6.json`.
|
|
36
|
+
|
|
37
|
+
<details>
|
|
38
|
+
<summary><strong>Manual setup (without wizard)</strong></summary>
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
cp mach6.example.json mach6.json
|
|
42
|
+
cp .env.example .env
|
|
43
|
+
# Edit both files — set API keys, channel tokens, workspace path, ownerIds
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
</details>
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## 🏗 Architecture
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
┌──────────────┐
|
|
54
|
+
│ Web UI │
|
|
55
|
+
│ :3006 │
|
|
56
|
+
└──────┬───────┘
|
|
57
|
+
│ SSE
|
|
58
|
+
┌──────────┐ ┌──────────┐ ┌──┴───────────┐ ┌──────────┐ ┌─────────┐
|
|
59
|
+
│ Discord │──│ Router │──│ Message Bus │──│ Agent │──│ Provider│──→ LLM
|
|
60
|
+
│ WhatsApp │ │ Policy │ │ Priority Q │ │ Runner │ │ (swap) │
|
|
61
|
+
│ HTTP API │ │ Dedup │ │ Coalesce │ │ Tools │ └─────────┘
|
|
62
|
+
└──────────┘ └──────────┘ │ Interrupt │ │ Abort │
|
|
63
|
+
│ Backpressure│ │ Iterate │
|
|
64
|
+
└──────────────┘ └──────────┘
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
| Layer | What it does |
|
|
68
|
+
|-------|-------------|
|
|
69
|
+
| **Channels** | Discord (discord.js), WhatsApp (Baileys v7). Adapter pattern — add any platform. |
|
|
70
|
+
| **Router** | Policy enforcement, JID normalization, deduplication, interrupt detection, priority. |
|
|
71
|
+
| **Message Bus** | Priority queue with interrupt bypass, message coalescing, backpressure management. |
|
|
72
|
+
| **Agent Runner** | Agentic loop — tool calling, context management, abort signals, iteration limits. |
|
|
73
|
+
| **Providers** | GitHub Copilot, Anthropic, OpenAI, Gladius (local). Hot-swappable mid-session. |
|
|
74
|
+
| **Tools** | 18 built-in. File I/O, shell, browser, TTS, memory, process management, messaging. |
|
|
75
|
+
| **Sessions** | Persistent, labeled, TTL-aware. Sub-agent spawning up to depth 3. |
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## 🔥 What Makes Mach6 Different
|
|
80
|
+
|
|
81
|
+
### Real-Time Interrupts
|
|
82
|
+
|
|
83
|
+
Most agent frameworks are request-response: you send a message, you wait, you get a reply. If the agent is mid-turn, your new message queues silently. You can't stop it. You can't redirect it.
|
|
84
|
+
|
|
85
|
+
**Mach6 doesn't work that way.** Every message is priority-classified in real-time:
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
interrupt → Bypasses queue. Cancels active turn immediately.
|
|
89
|
+
high → Skips coalescing. Next in line.
|
|
90
|
+
normal → Standard processing with coalescing.
|
|
91
|
+
low → Reactions, group mentions. Queued politely.
|
|
92
|
+
background → Typing indicators. Dropped under backpressure.
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Send "stop" while the agent is mid-thought → the agent stops. Immediately. Not after the current tool call. Not after the current paragraph. **Now.**
|
|
96
|
+
|
|
97
|
+
### Message Coalescing
|
|
98
|
+
|
|
99
|
+
Three messages in rapid succession? Mach6 buffers and merges them:
|
|
100
|
+
|
|
101
|
+
```
|
|
102
|
+
"hey" → buffered
|
|
103
|
+
"can you" → buffered
|
|
104
|
+
"check the logs" → 2s timer expires → merged into one envelope
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
One coherent request, one turn, no wasted tokens.
|
|
108
|
+
|
|
109
|
+
### Single Process, Zero Infrastructure
|
|
110
|
+
|
|
111
|
+
One Node.js daemon. No Docker. No Redis. No Kubernetes. No microservices. Install, configure, run. It's a binary that talks to LLMs and messaging platforms. That's it.
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## ⚙ Configuration
|
|
116
|
+
|
|
117
|
+
### `mach6.json` — Agent configuration
|
|
118
|
+
|
|
119
|
+
```jsonc
|
|
120
|
+
{
|
|
121
|
+
"defaultProvider": "github-copilot",
|
|
122
|
+
"defaultModel": "claude-opus-4-6",
|
|
123
|
+
"maxTokens": 8192,
|
|
124
|
+
"maxIterations": 50,
|
|
125
|
+
"temperature": 0.3,
|
|
126
|
+
|
|
127
|
+
// Use forward slashes on all platforms
|
|
128
|
+
// Windows: "C:/Users/you/workspace"
|
|
129
|
+
"workspace": "/home/you/workspace",
|
|
130
|
+
"sessionsDir": ".sessions",
|
|
131
|
+
|
|
132
|
+
"providers": {
|
|
133
|
+
"github-copilot": {},
|
|
134
|
+
"anthropic": {},
|
|
135
|
+
"openai": {},
|
|
136
|
+
"gladius": { "baseUrl": "http://127.0.0.1:8741" }
|
|
137
|
+
},
|
|
138
|
+
|
|
139
|
+
"ownerIds": [
|
|
140
|
+
"your-discord-user-id",
|
|
141
|
+
"your-phone@s.whatsapp.net"
|
|
142
|
+
],
|
|
143
|
+
|
|
144
|
+
"discord": {
|
|
145
|
+
"enabled": true,
|
|
146
|
+
"token": "${DISCORD_BOT_TOKEN}",
|
|
147
|
+
"botId": "${DISCORD_CLIENT_ID}",
|
|
148
|
+
"siblingBotIds": [],
|
|
149
|
+
"policy": {
|
|
150
|
+
"dmPolicy": "allowlist",
|
|
151
|
+
"groupPolicy": "mention-only",
|
|
152
|
+
"requireMention": true,
|
|
153
|
+
"allowedSenders": ["your-discord-user-id"],
|
|
154
|
+
"allowedGroups": []
|
|
155
|
+
}
|
|
156
|
+
},
|
|
157
|
+
|
|
158
|
+
"whatsapp": {
|
|
159
|
+
"enabled": true,
|
|
160
|
+
"authDir": "~/.mach6/whatsapp-auth",
|
|
161
|
+
"phoneNumber": "your-phone-number",
|
|
162
|
+
"autoRead": true,
|
|
163
|
+
"policy": {
|
|
164
|
+
"dmPolicy": "allowlist",
|
|
165
|
+
"groupPolicy": "mention-only",
|
|
166
|
+
"allowedSenders": ["your-phone@s.whatsapp.net"],
|
|
167
|
+
"allowedGroups": []
|
|
168
|
+
}
|
|
169
|
+
},
|
|
170
|
+
|
|
171
|
+
"apiPort": 3006
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
All string values support `${ENV_VAR}` interpolation.
|
|
176
|
+
|
|
177
|
+
### `.env` — Secrets
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
# LLM Providers
|
|
181
|
+
ANTHROPIC_API_KEY=sk-ant-...
|
|
182
|
+
OPENAI_API_KEY=sk-...
|
|
183
|
+
|
|
184
|
+
# GitHub Copilot — usually automatic via `gh auth login`
|
|
185
|
+
# COPILOT_GITHUB_TOKEN=
|
|
186
|
+
|
|
187
|
+
# Discord
|
|
188
|
+
DISCORD_BOT_TOKEN=
|
|
189
|
+
DISCORD_CLIENT_ID=
|
|
190
|
+
|
|
191
|
+
# HTTP API authentication
|
|
192
|
+
MACH6_API_KEY=
|
|
193
|
+
|
|
194
|
+
# Port (default: 3006)
|
|
195
|
+
MACH6_PORT=3006
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
> Run `mach6 init` to generate both files interactively.
|
|
199
|
+
|
|
200
|
+
---
|
|
201
|
+
|
|
202
|
+
## 🧠 Providers
|
|
203
|
+
|
|
204
|
+
| Provider | Config Key | How it authenticates |
|
|
205
|
+
|----------|-----------|---------------------|
|
|
206
|
+
| **GitHub Copilot** | `github-copilot` | Auto-resolved (see below) — no API key needed |
|
|
207
|
+
| **Anthropic** | `anthropic` | `ANTHROPIC_API_KEY` env var |
|
|
208
|
+
| **OpenAI** | `openai` | `OPENAI_API_KEY` env var |
|
|
209
|
+
| **Gladius** | `gladius` | Local HTTP endpoint |
|
|
210
|
+
|
|
211
|
+
### GitHub Copilot token resolution
|
|
212
|
+
|
|
213
|
+
No API key required if `gh` CLI is installed and authenticated. Token resolves in order:
|
|
214
|
+
|
|
215
|
+
1. `COPILOT_GITHUB_TOKEN` env var
|
|
216
|
+
2. `~/.copilot-cli-access-token` file
|
|
217
|
+
3. `GH_TOKEN` / `GITHUB_TOKEN` env vars
|
|
218
|
+
4. `~/.config/github-copilot/hosts.json` (Linux/macOS)
|
|
219
|
+
5. `%APPDATA%\github-copilot\hosts.json` (Windows)
|
|
220
|
+
6. `gh auth token` CLI fallback (all platforms)
|
|
221
|
+
|
|
222
|
+
### Available models (via Copilot proxy)
|
|
223
|
+
|
|
224
|
+
| Model | Config value |
|
|
225
|
+
|-------|-------------|
|
|
226
|
+
| Claude Opus 4.6 | `claude-opus-4-6` |
|
|
227
|
+
| Claude Sonnet 4 | `claude-sonnet-4` |
|
|
228
|
+
| GPT-4o | `gpt-4o` |
|
|
229
|
+
| o3-mini | `o3-mini` |
|
|
230
|
+
|
|
231
|
+
Providers are hot-swappable mid-session via `/provider` and `/model` commands.
|
|
232
|
+
|
|
233
|
+
---
|
|
234
|
+
|
|
235
|
+
## 🛠 Tools
|
|
236
|
+
|
|
237
|
+
18 built-in tools, available to the agent by default:
|
|
238
|
+
|
|
239
|
+
| Tool | Description |
|
|
240
|
+
|------|------------|
|
|
241
|
+
| `read` | Read file contents (with offset/limit for large files) |
|
|
242
|
+
| `write` | Write/create files (auto-creates parent directories) |
|
|
243
|
+
| `edit` | Surgical find-and-replace editing |
|
|
244
|
+
| `exec` | Execute shell commands |
|
|
245
|
+
| `image` | Analyze images with vision models |
|
|
246
|
+
| `web_fetch` | Fetch URLs, strip HTML to text |
|
|
247
|
+
| `tts` | Text-to-speech (Edge TTS, multiple voices) |
|
|
248
|
+
| `memory_search` | Hybrid BM25 + vector search over indexed files |
|
|
249
|
+
| `comb_recall` | Recall persistent session-to-session memory |
|
|
250
|
+
| `comb_stage` | Stage information for next session |
|
|
251
|
+
| `message` | Send messages, media, and reactions to any channel |
|
|
252
|
+
| `typing` | Send typing indicators |
|
|
253
|
+
| `presence` | Update presence status |
|
|
254
|
+
| `delete_message` | Delete messages |
|
|
255
|
+
| `mark_read` | Send read receipts |
|
|
256
|
+
| `process_start` | Start background processes |
|
|
257
|
+
| `process_poll` | Poll background process output |
|
|
258
|
+
| `process_kill` | Kill background processes |
|
|
259
|
+
| `process_list` | List background processes |
|
|
260
|
+
| `spawn` | Spawn sub-agents (up to depth 3) |
|
|
261
|
+
|
|
262
|
+
Tools are sandboxed per-session via the policy engine. MCP bridge available for external tool servers.
|
|
263
|
+
|
|
264
|
+
---
|
|
265
|
+
|
|
266
|
+
## 🖥 Web UI
|
|
267
|
+
|
|
268
|
+
Mach6 ships with a built-in web interface at `http://localhost:3006`:
|
|
269
|
+
|
|
270
|
+
- **Session management** — create, switch, delete sessions
|
|
271
|
+
- **Streaming responses** — real-time SSE with tool call visualization
|
|
272
|
+
- **Config panel** — change provider, model, temperature, API keys live
|
|
273
|
+
- **Sub-agent monitoring** — view and kill running sub-agents
|
|
274
|
+
- **Generative UI** — file reads, exec outputs, and fetches render as rich cards
|
|
275
|
+
|
|
276
|
+
No build step. No npm dependencies. One static HTML file.
|
|
277
|
+
|
|
278
|
+
---
|
|
279
|
+
|
|
280
|
+
## 🖥 CLI
|
|
281
|
+
|
|
282
|
+
### Interactive REPL
|
|
283
|
+
|
|
284
|
+
```bash
|
|
285
|
+
node dist/index.js --config=mach6.json
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
```
|
|
289
|
+
Mach6 v0.2 | github-copilot/claude-opus-4-6 | session: default
|
|
290
|
+
Tools (18): read, write, edit, exec, image, web_fetch, tts, ...
|
|
291
|
+
Type /help for commands
|
|
292
|
+
|
|
293
|
+
❯ What's in the logs?
|
|
294
|
+
⚡ exec
|
|
295
|
+
✓ exec tail -50 /var/log/syslog
|
|
296
|
+
...
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
### Commands
|
|
300
|
+
|
|
301
|
+
| Command | Description |
|
|
302
|
+
|---------|------------|
|
|
303
|
+
| `/help` | Show all commands |
|
|
304
|
+
| `/tools` | List available tools |
|
|
305
|
+
| `/model <name>` | Switch model mid-session |
|
|
306
|
+
| `/provider <name>` | Switch provider mid-session |
|
|
307
|
+
| `/spawn <task>` | Spawn a sub-agent |
|
|
308
|
+
| `/status` | Session stats (tokens, tool usage) |
|
|
309
|
+
| `/sessions` | List all sessions |
|
|
310
|
+
| `/history [N]` | Show last N messages |
|
|
311
|
+
| `/clear` | Clear current session |
|
|
312
|
+
| `/quit` | Exit |
|
|
313
|
+
|
|
314
|
+
### One-shot mode
|
|
315
|
+
|
|
316
|
+
```bash
|
|
317
|
+
node dist/index.js "Summarize the README in this directory"
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
---
|
|
321
|
+
|
|
322
|
+
## 🐧 Running as a Service
|
|
323
|
+
|
|
324
|
+
### Linux (systemd)
|
|
325
|
+
|
|
326
|
+
```bash
|
|
327
|
+
# Copy the included service file
|
|
328
|
+
sudo cp mach6-gateway.service /etc/systemd/system/
|
|
329
|
+
# Edit it — set your paths and user
|
|
330
|
+
sudo systemctl enable --now mach6-gateway
|
|
331
|
+
|
|
332
|
+
# Hot-reload config without restarting:
|
|
333
|
+
kill -USR1 $(pgrep -f "gateway/daemon.js")
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
### macOS (launchd)
|
|
337
|
+
|
|
338
|
+
Create `~/Library/LaunchAgents/com.mach6.gateway.plist` pointing to `node dist/gateway/daemon.js`.
|
|
339
|
+
|
|
340
|
+
### Windows
|
|
341
|
+
|
|
342
|
+
Use [NSSM](https://nssm.cc/) or Task Scheduler to run `node dist/gateway/daemon.js --config=mach6.json`.
|
|
343
|
+
|
|
344
|
+
> **Note:** `SIGUSR1` hot-reload is not available on Windows. Restart the process to reload config.
|
|
345
|
+
|
|
346
|
+
---
|
|
347
|
+
|
|
348
|
+
## 📁 Project Structure
|
|
349
|
+
|
|
350
|
+
```
|
|
351
|
+
mach6/
|
|
352
|
+
├── src/
|
|
353
|
+
│ ├── agent/ # Runner, context manager, system prompt builder
|
|
354
|
+
│ ├── boot/ # Boot sequence & validation
|
|
355
|
+
│ ├── channels/ # Adapter pattern — Discord, WhatsApp, router, bus
|
|
356
|
+
│ │ ├── bus.ts # Priority queue, coalescing, interrupts, backpressure
|
|
357
|
+
│ │ ├── router.ts # Policy, dedup, JID normalization, priority
|
|
358
|
+
│ │ └── adapters/ # Discord (discord.js), WhatsApp (Baileys v7)
|
|
359
|
+
│ ├── cli/ # Interactive setup wizard
|
|
360
|
+
│ ├── config/ # Config loader, validator, env interpolation
|
|
361
|
+
│ ├── cron/ # Cron budget management
|
|
362
|
+
│ ├── formatters/ # Platform-aware markdown formatting
|
|
363
|
+
│ ├── gateway/ # Persistent daemon — signals, hot-reload, turns
|
|
364
|
+
│ ├── heartbeat/ # Activity-aware periodic health checks
|
|
365
|
+
│ ├── memory/ # Index integrity checks
|
|
366
|
+
│ ├── providers/ # LLM providers — Copilot, Anthropic, OpenAI, Gladius
|
|
367
|
+
│ ├── security/ # Input sanitization
|
|
368
|
+
│ ├── sessions/ # Session store, queue, sub-agents
|
|
369
|
+
│ ├── tools/ # 18 built-in tools, policy engine, registry, MCP bridge
|
|
370
|
+
│ └── web/ # Web UI server (SSE streaming, static serving)
|
|
371
|
+
├── web/ # Web UI (single HTML file)
|
|
372
|
+
├── mach6.example.json # Example config
|
|
373
|
+
├── .env.example # Example environment variables
|
|
374
|
+
├── mach6.sh # Linux/macOS start script
|
|
375
|
+
├── mach6.ps1 # Windows start script
|
|
376
|
+
└── mach6-gateway.service # systemd unit file
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
---
|
|
380
|
+
|
|
381
|
+
## 🔒 Hardening
|
|
382
|
+
|
|
383
|
+
20 production pain points addressed:
|
|
384
|
+
|
|
385
|
+
- **Config validation** with human-readable diagnostics at boot
|
|
386
|
+
- **Context monitor** with progressive warnings (70/80/90% thresholds)
|
|
387
|
+
- **Priority message queue** — real messages never drop, only background signals shed under backpressure
|
|
388
|
+
- **Tool policy engine** — scope available tools per session and security tier
|
|
389
|
+
- **Provider diagnostics** — health checks and automatic failover
|
|
390
|
+
- **Activity-aware heartbeat** — adapts frequency to system load
|
|
391
|
+
- **Cron budget management** — prevents runaway scheduled tasks
|
|
392
|
+
- **Boot sequence validation** — catch misconfigurations before they become incidents
|
|
393
|
+
- **JID normalization** for WhatsApp Baileys v7 (device suffix stripping)
|
|
394
|
+
- **Abort signal propagation** through agent runner → LLM stream → tool execution
|
|
395
|
+
- **MCP bridge** for connecting external tool servers
|
|
396
|
+
- **Sibling bot yield** — @mention one bot, only that one responds
|
|
397
|
+
|
|
398
|
+
---
|
|
399
|
+
|
|
400
|
+
## 📊 Stats
|
|
401
|
+
|
|
402
|
+
| Metric | Value |
|
|
403
|
+
|--------|-------|
|
|
404
|
+
| Lines of TypeScript | ~8,400 |
|
|
405
|
+
| Built-in tools | 18 |
|
|
406
|
+
| LLM providers | 4 |
|
|
407
|
+
| Channel adapters | 2 + HTTP API |
|
|
408
|
+
| Cold boot to connected | ~2.3s |
|
|
409
|
+
| External runtime deps | Node.js only |
|
|
410
|
+
|
|
411
|
+
---
|
|
412
|
+
|
|
413
|
+
## 🌐 Platform Compatibility
|
|
414
|
+
|
|
415
|
+
| Feature | Windows | Linux | macOS |
|
|
416
|
+
|---------|---------|-------|-------|
|
|
417
|
+
| Gateway daemon | ✅ | ✅ | ✅ |
|
|
418
|
+
| Discord adapter | ✅ | ✅ | ✅ |
|
|
419
|
+
| WhatsApp adapter | ✅ | ✅ | ✅ |
|
|
420
|
+
| HTTP API + Web UI | ✅ | ✅ | ✅ |
|
|
421
|
+
| CLI (REPL + one-shot) | ✅ | ✅ | ✅ |
|
|
422
|
+
| Hot-reload (SIGUSR1) | ❌ | ✅ | ✅ |
|
|
423
|
+
| Service manager | Task Scheduler | systemd | launchd |
|
|
424
|
+
| Temp directory | `%TEMP%` | `/tmp` | `/tmp` |
|
|
425
|
+
| Home directory | `%USERPROFILE%` | `~` | `~` |
|
|
426
|
+
|
|
427
|
+
All paths resolved via `os.tmpdir()` and `os.homedir()` — zero hardcoded Unix paths.
|
|
428
|
+
|
|
429
|
+
---
|
|
430
|
+
|
|
431
|
+
## 📜 History
|
|
432
|
+
|
|
433
|
+
| Date | Milestone |
|
|
434
|
+
|------|----------|
|
|
435
|
+
| **Feb 22, 2026** | Built from scratch. WhatsApp, Discord, gateway, config, tools, sessions. |
|
|
436
|
+
| **Feb 22, 2026** | 14/14 smoke tests. 20 hardening fixes. Flipped to production same day. |
|
|
437
|
+
| **Feb 23, 2026** | Open-sourced. MIT license. |
|
|
438
|
+
| **Feb 28, 2026** | Cross-platform (Windows/Linux/macOS). CLI wizard. v1.0.0. |
|
|
439
|
+
|
|
440
|
+
---
|
|
441
|
+
|
|
442
|
+
## 📄 License
|
|
443
|
+
|
|
444
|
+
[MIT](LICENSE) — do whatever you want with it.
|
|
445
|
+
|
|
446
|
+
---
|
|
447
|
+
|
|
448
|
+
<div align="center">
|
|
449
|
+
|
|
450
|
+
Built by **[Artifact Virtual](https://artifactvirtual.com)**
|
|
451
|
+
|
|
452
|
+
Open-sourced because infrastructure wants to be free.
|
|
453
|
+
|
|
454
|
+
</div>
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { Message } from '../providers/types.js';
|
|
2
|
+
export interface ContextMonitorConfig {
|
|
3
|
+
maxContextTokens: number;
|
|
4
|
+
warnThreshold?: number;
|
|
5
|
+
compactThreshold?: number;
|
|
6
|
+
emergencyThreshold?: number;
|
|
7
|
+
transcriptDir?: string;
|
|
8
|
+
onCombStage?: (content: string) => Promise<void>;
|
|
9
|
+
}
|
|
10
|
+
export type ContextHealth = 'ok' | 'warning' | 'compacting' | 'emergency';
|
|
11
|
+
export interface ContextStatus {
|
|
12
|
+
totalTokens: number;
|
|
13
|
+
maxTokens: number;
|
|
14
|
+
usage: number;
|
|
15
|
+
health: ContextHealth;
|
|
16
|
+
messageCount: number;
|
|
17
|
+
}
|
|
18
|
+
export declare class ContextMonitor {
|
|
19
|
+
private config;
|
|
20
|
+
private transcriptDir;
|
|
21
|
+
private onCombStage?;
|
|
22
|
+
private hasWarned;
|
|
23
|
+
constructor(cfg: ContextMonitorConfig);
|
|
24
|
+
/** Check current context health without modifying anything */
|
|
25
|
+
check(messages: Message[]): ContextStatus;
|
|
26
|
+
/**
|
|
27
|
+
* Check and act: returns (possibly compacted) messages.
|
|
28
|
+
* - warning: logs, returns as-is
|
|
29
|
+
* - compacting: COMB stage + summarize old messages
|
|
30
|
+
* - emergency: save transcript to disk, hard-truncate
|
|
31
|
+
*/
|
|
32
|
+
manage(messages: Message[]): Promise<Message[]>;
|
|
33
|
+
/** Summarize old messages, keep system + recent */
|
|
34
|
+
private compact;
|
|
35
|
+
/** Emergency: save full transcript, keep only last N messages */
|
|
36
|
+
private hardTruncate;
|
|
37
|
+
private buildSummary;
|
|
38
|
+
private saveTranscript;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=context-monitor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-monitor.d.ts","sourceRoot":"","sources":["../../src/agent/context-monitor.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAErD,MAAM,WAAW,oBAAoB;IACnC,gBAAgB,EAAE,MAAM,CAAC;IACzB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAClD;AAED,MAAM,MAAM,aAAa,GAAG,IAAI,GAAG,SAAS,GAAG,YAAY,GAAG,WAAW,CAAC;AAE1E,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,aAAa,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;CACtB;AAiBD,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAyH;IACvI,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,WAAW,CAAC,CAAqC;IACzD,OAAO,CAAC,SAAS,CAAS;gBAEd,GAAG,EAAE,oBAAoB;IAWrC,8DAA8D;IAC9D,KAAK,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,aAAa;IAYzC;;;;;OAKG;IACG,MAAM,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IAqCrD,mDAAmD;IACnD,OAAO,CAAC,OAAO;IAwBf,iEAAiE;IACjE,OAAO,CAAC,YAAY;IAQpB,OAAO,CAAC,YAAY;YAUN,cAAc;CAU7B"}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
// Mach6 — Proactive Context Management (fixes Pain #3)
|
|
2
|
+
// Track tokens in real-time. Compact before overflow. Never hit the wall.
|
|
3
|
+
import os from 'node:os';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
/** Rough token estimate: ~4 chars per token */
|
|
6
|
+
function estimateTokens(text) {
|
|
7
|
+
return Math.ceil(text.length / 4);
|
|
8
|
+
}
|
|
9
|
+
function messageTokens(msg) {
|
|
10
|
+
if (typeof msg.content === 'string')
|
|
11
|
+
return estimateTokens(msg.content);
|
|
12
|
+
return msg.content.reduce((sum, b) => {
|
|
13
|
+
if (b.text)
|
|
14
|
+
return sum + estimateTokens(b.text);
|
|
15
|
+
if (b.content)
|
|
16
|
+
return sum + estimateTokens(b.content);
|
|
17
|
+
if (b.input)
|
|
18
|
+
return sum + estimateTokens(JSON.stringify(b.input));
|
|
19
|
+
return sum + 50;
|
|
20
|
+
}, 0);
|
|
21
|
+
}
|
|
22
|
+
export class ContextMonitor {
|
|
23
|
+
config;
|
|
24
|
+
transcriptDir;
|
|
25
|
+
onCombStage;
|
|
26
|
+
hasWarned = false;
|
|
27
|
+
constructor(cfg) {
|
|
28
|
+
this.config = {
|
|
29
|
+
maxContextTokens: cfg.maxContextTokens,
|
|
30
|
+
warnThreshold: cfg.warnThreshold ?? 0.7,
|
|
31
|
+
compactThreshold: cfg.compactThreshold ?? 0.8,
|
|
32
|
+
emergencyThreshold: cfg.emergencyThreshold ?? 0.9,
|
|
33
|
+
};
|
|
34
|
+
this.transcriptDir = cfg.transcriptDir ?? path.join(os.tmpdir(), 'mach6-transcripts');
|
|
35
|
+
this.onCombStage = cfg.onCombStage;
|
|
36
|
+
}
|
|
37
|
+
/** Check current context health without modifying anything */
|
|
38
|
+
check(messages) {
|
|
39
|
+
const totalTokens = messages.reduce((s, m) => s + messageTokens(m), 0);
|
|
40
|
+
const usage = totalTokens / this.config.maxContextTokens;
|
|
41
|
+
let health = 'ok';
|
|
42
|
+
if (usage >= this.config.emergencyThreshold)
|
|
43
|
+
health = 'emergency';
|
|
44
|
+
else if (usage >= this.config.compactThreshold)
|
|
45
|
+
health = 'compacting';
|
|
46
|
+
else if (usage >= this.config.warnThreshold)
|
|
47
|
+
health = 'warning';
|
|
48
|
+
return { totalTokens, maxTokens: this.config.maxContextTokens, usage, health, messageCount: messages.length };
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Check and act: returns (possibly compacted) messages.
|
|
52
|
+
* - warning: logs, returns as-is
|
|
53
|
+
* - compacting: COMB stage + summarize old messages
|
|
54
|
+
* - emergency: save transcript to disk, hard-truncate
|
|
55
|
+
*/
|
|
56
|
+
async manage(messages) {
|
|
57
|
+
const status = this.check(messages);
|
|
58
|
+
if (status.health === 'ok') {
|
|
59
|
+
this.hasWarned = false;
|
|
60
|
+
return messages;
|
|
61
|
+
}
|
|
62
|
+
if (status.health === 'warning') {
|
|
63
|
+
if (!this.hasWarned) {
|
|
64
|
+
console.warn(`⚠️ Context at ${(status.usage * 100).toFixed(0)}% (${status.totalTokens}/${status.maxTokens} tokens)`);
|
|
65
|
+
this.hasWarned = true;
|
|
66
|
+
}
|
|
67
|
+
return messages;
|
|
68
|
+
}
|
|
69
|
+
// Before any compaction, stage to COMB
|
|
70
|
+
if (this.onCombStage) {
|
|
71
|
+
const summary = this.buildSummary(messages);
|
|
72
|
+
try {
|
|
73
|
+
await this.onCombStage(summary);
|
|
74
|
+
}
|
|
75
|
+
catch (err) {
|
|
76
|
+
console.error('COMB stage failed during compaction:', err);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
if (status.health === 'emergency') {
|
|
80
|
+
console.error(`🚨 Context EMERGENCY at ${(status.usage * 100).toFixed(0)}% — flushing to disk`);
|
|
81
|
+
await this.saveTranscript(messages);
|
|
82
|
+
return this.hardTruncate(messages, 10);
|
|
83
|
+
}
|
|
84
|
+
// compacting
|
|
85
|
+
console.warn(`🔄 Context at ${(status.usage * 100).toFixed(0)}% — auto-compacting`);
|
|
86
|
+
return this.compact(messages);
|
|
87
|
+
}
|
|
88
|
+
/** Summarize old messages, keep system + recent */
|
|
89
|
+
compact(messages) {
|
|
90
|
+
const system = messages.filter(m => m.role === 'system');
|
|
91
|
+
const rest = messages.filter(m => m.role !== 'system');
|
|
92
|
+
// Keep last 40% of non-system messages
|
|
93
|
+
const keepCount = Math.max(10, Math.floor(rest.length * 0.4));
|
|
94
|
+
const old = rest.slice(0, rest.length - keepCount);
|
|
95
|
+
const recent = rest.slice(rest.length - keepCount);
|
|
96
|
+
// Build summary of old messages
|
|
97
|
+
const summaryParts = ['[Context compacted. Summary of earlier conversation:]'];
|
|
98
|
+
for (const msg of old) {
|
|
99
|
+
const text = typeof msg.content === 'string' ? msg.content : '[structured content]';
|
|
100
|
+
const preview = text.slice(0, 200);
|
|
101
|
+
summaryParts.push(`${msg.role}: ${preview}${text.length > 200 ? '...' : ''}`);
|
|
102
|
+
}
|
|
103
|
+
const summaryMsg = {
|
|
104
|
+
role: 'user',
|
|
105
|
+
content: summaryParts.join('\n').slice(0, 2000),
|
|
106
|
+
};
|
|
107
|
+
return [...system, summaryMsg, ...recent];
|
|
108
|
+
}
|
|
109
|
+
/** Emergency: save full transcript, keep only last N messages */
|
|
110
|
+
hardTruncate(messages, keepLast) {
|
|
111
|
+
const system = messages.filter(m => m.role === 'system');
|
|
112
|
+
const rest = messages.filter(m => m.role !== 'system');
|
|
113
|
+
const kept = rest.slice(-keepLast);
|
|
114
|
+
const notice = { role: 'user', content: '[Emergency context flush. Earlier messages saved to disk. Recent context only.]' };
|
|
115
|
+
return [...system, notice, ...kept];
|
|
116
|
+
}
|
|
117
|
+
buildSummary(messages) {
|
|
118
|
+
const parts = [`Context snapshot at ${new Date().toISOString()} (${messages.length} messages)`];
|
|
119
|
+
for (const msg of messages) {
|
|
120
|
+
if (msg.role === 'system')
|
|
121
|
+
continue;
|
|
122
|
+
const text = typeof msg.content === 'string' ? msg.content : JSON.stringify(msg.content);
|
|
123
|
+
parts.push(`[${msg.role}] ${text.slice(0, 500)}`);
|
|
124
|
+
}
|
|
125
|
+
return parts.join('\n');
|
|
126
|
+
}
|
|
127
|
+
async saveTranscript(messages) {
|
|
128
|
+
// Dynamic import to avoid top-level fs dependency issues
|
|
129
|
+
const fs = await import('node:fs');
|
|
130
|
+
const path = await import('node:path');
|
|
131
|
+
fs.mkdirSync(this.transcriptDir, { recursive: true });
|
|
132
|
+
const filename = `transcript-${Date.now()}.json`;
|
|
133
|
+
const filepath = path.join(this.transcriptDir, filename);
|
|
134
|
+
fs.writeFileSync(filepath, JSON.stringify(messages, null, 2));
|
|
135
|
+
console.log(`📝 Transcript saved: ${filepath}`);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
//# sourceMappingURL=context-monitor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-monitor.js","sourceRoot":"","sources":["../../src/agent/context-monitor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Message } from '../providers/types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Truncate message history to fit within a token budget.
|
|
4
|
+
* Strategy: keep system prompt + last N messages, drop oldest first.
|
|
5
|
+
* CRITICAL: tool_use/tool_result messages must stay paired.
|
|
6
|
+
*/
|
|
7
|
+
export declare function truncateContext(messages: Message[], maxTokens: number): Message[];
|
|
8
|
+
//# sourceMappingURL=context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/agent/context.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAgB,MAAM,uBAAuB,CAAC;AAkFnE;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,EAAE,CAuFjF"}
|