@songsid/agend 0.0.1
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 +210 -0
- package/README.zh-TW.md +134 -0
- package/dist/access-path.d.ts +10 -0
- package/dist/access-path.js +32 -0
- package/dist/access-path.js.map +1 -0
- package/dist/adapter-world.d.ts +25 -0
- package/dist/adapter-world.js +41 -0
- package/dist/adapter-world.js.map +1 -0
- package/dist/agent-cli-instructions.md +50 -0
- package/dist/agent-cli.d.ts +2 -0
- package/dist/agent-cli.js +200 -0
- package/dist/agent-cli.js.map +1 -0
- package/dist/agent-endpoint.d.ts +25 -0
- package/dist/agent-endpoint.js +162 -0
- package/dist/agent-endpoint.js.map +1 -0
- package/dist/backend/antigravity.d.ts +17 -0
- package/dist/backend/antigravity.js +98 -0
- package/dist/backend/antigravity.js.map +1 -0
- package/dist/backend/claude-code.d.ts +23 -0
- package/dist/backend/claude-code.js +171 -0
- package/dist/backend/claude-code.js.map +1 -0
- package/dist/backend/codex.d.ts +18 -0
- package/dist/backend/codex.js +160 -0
- package/dist/backend/codex.js.map +1 -0
- package/dist/backend/factory.d.ts +2 -0
- package/dist/backend/factory.js +28 -0
- package/dist/backend/factory.js.map +1 -0
- package/dist/backend/gemini-cli.d.ts +17 -0
- package/dist/backend/gemini-cli.js +163 -0
- package/dist/backend/gemini-cli.js.map +1 -0
- package/dist/backend/index.d.ts +7 -0
- package/dist/backend/index.js +7 -0
- package/dist/backend/index.js.map +1 -0
- package/dist/backend/kiro.d.ts +17 -0
- package/dist/backend/kiro.js +147 -0
- package/dist/backend/kiro.js.map +1 -0
- package/dist/backend/marker-utils.d.ts +13 -0
- package/dist/backend/marker-utils.js +64 -0
- package/dist/backend/marker-utils.js.map +1 -0
- package/dist/backend/mock.d.ts +25 -0
- package/dist/backend/mock.js +85 -0
- package/dist/backend/mock.js.map +1 -0
- package/dist/backend/opencode.d.ts +16 -0
- package/dist/backend/opencode.js +136 -0
- package/dist/backend/opencode.js.map +1 -0
- package/dist/backend/types.d.ts +86 -0
- package/dist/backend/types.js +33 -0
- package/dist/backend/types.js.map +1 -0
- package/dist/channel/access-manager.d.ts +18 -0
- package/dist/channel/access-manager.js +153 -0
- package/dist/channel/access-manager.js.map +1 -0
- package/dist/channel/adapters/telegram.d.ts +63 -0
- package/dist/channel/adapters/telegram.js +646 -0
- package/dist/channel/adapters/telegram.js.map +1 -0
- package/dist/channel/attachment-handler.d.ts +15 -0
- package/dist/channel/attachment-handler.js +88 -0
- package/dist/channel/attachment-handler.js.map +1 -0
- package/dist/channel/factory.d.ts +12 -0
- package/dist/channel/factory.js +67 -0
- package/dist/channel/factory.js.map +1 -0
- package/dist/channel/ipc-bridge.d.ts +26 -0
- package/dist/channel/ipc-bridge.js +220 -0
- package/dist/channel/ipc-bridge.js.map +1 -0
- package/dist/channel/mcp-server.d.ts +10 -0
- package/dist/channel/mcp-server.js +288 -0
- package/dist/channel/mcp-server.js.map +1 -0
- package/dist/channel/mcp-tools.d.ts +17 -0
- package/dist/channel/mcp-tools.js +110 -0
- package/dist/channel/mcp-tools.js.map +1 -0
- package/dist/channel/message-bus.d.ts +17 -0
- package/dist/channel/message-bus.js +86 -0
- package/dist/channel/message-bus.js.map +1 -0
- package/dist/channel/message-queue.d.ts +39 -0
- package/dist/channel/message-queue.js +253 -0
- package/dist/channel/message-queue.js.map +1 -0
- package/dist/channel/tool-router.d.ts +6 -0
- package/dist/channel/tool-router.js +75 -0
- package/dist/channel/tool-router.js.map +1 -0
- package/dist/channel/tool-tracker.d.ts +13 -0
- package/dist/channel/tool-tracker.js +58 -0
- package/dist/channel/tool-tracker.js.map +1 -0
- package/dist/channel/types.d.ts +118 -0
- package/dist/channel/types.js +2 -0
- package/dist/channel/types.js.map +1 -0
- package/dist/chat-export.d.ts +4 -0
- package/dist/chat-export.js +91 -0
- package/dist/chat-export.js.map +1 -0
- package/dist/classic-channel-manager.d.ts +59 -0
- package/dist/classic-channel-manager.js +193 -0
- package/dist/classic-channel-manager.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +1833 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +9 -0
- package/dist/config.js +118 -0
- package/dist/config.js.map +1 -0
- package/dist/context-guardian.d.ts +26 -0
- package/dist/context-guardian.js +73 -0
- package/dist/context-guardian.js.map +1 -0
- package/dist/cost-guard.d.ts +36 -0
- package/dist/cost-guard.js +147 -0
- package/dist/cost-guard.js.map +1 -0
- package/dist/daemon-entry.d.ts +1 -0
- package/dist/daemon-entry.js +29 -0
- package/dist/daemon-entry.js.map +1 -0
- package/dist/daemon.d.ts +152 -0
- package/dist/daemon.js +1714 -0
- package/dist/daemon.js.map +1 -0
- package/dist/daily-summary.d.ts +13 -0
- package/dist/daily-summary.js +55 -0
- package/dist/daily-summary.js.map +1 -0
- package/dist/event-log.d.ts +36 -0
- package/dist/event-log.js +100 -0
- package/dist/event-log.js.map +1 -0
- package/dist/export-import.d.ts +2 -0
- package/dist/export-import.js +162 -0
- package/dist/export-import.js.map +1 -0
- package/dist/fleet-context.d.ts +61 -0
- package/dist/fleet-context.js +4 -0
- package/dist/fleet-context.js.map +1 -0
- package/dist/fleet-dashboard-html.d.ts +6 -0
- package/dist/fleet-dashboard-html.js +443 -0
- package/dist/fleet-dashboard-html.js.map +1 -0
- package/dist/fleet-health-server.d.ts +35 -0
- package/dist/fleet-health-server.js +290 -0
- package/dist/fleet-health-server.js.map +1 -0
- package/dist/fleet-instructions.d.ts +5 -0
- package/dist/fleet-instructions.js +161 -0
- package/dist/fleet-instructions.js.map +1 -0
- package/dist/fleet-manager.d.ts +212 -0
- package/dist/fleet-manager.js +3655 -0
- package/dist/fleet-manager.js.map +1 -0
- package/dist/fleet-rpc-handlers.d.ts +42 -0
- package/dist/fleet-rpc-handlers.js +356 -0
- package/dist/fleet-rpc-handlers.js.map +1 -0
- package/dist/fleet-system-prompt.d.ts +11 -0
- package/dist/fleet-system-prompt.js +61 -0
- package/dist/fleet-system-prompt.js.map +1 -0
- package/dist/general-knowledge/skills.md +177 -0
- package/dist/hang-detector.d.ts +16 -0
- package/dist/hang-detector.js +53 -0
- package/dist/hang-detector.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/instance-lifecycle.d.ts +90 -0
- package/dist/instance-lifecycle.js +592 -0
- package/dist/instance-lifecycle.js.map +1 -0
- package/dist/instructions.d.ts +15 -0
- package/dist/instructions.js +90 -0
- package/dist/instructions.js.map +1 -0
- package/dist/logger.d.ts +7 -0
- package/dist/logger.js +84 -0
- package/dist/logger.js.map +1 -0
- package/dist/outbound-handlers.d.ts +51 -0
- package/dist/outbound-handlers.js +739 -0
- package/dist/outbound-handlers.js.map +1 -0
- package/dist/outbound-schemas.d.ts +238 -0
- package/dist/outbound-schemas.js +248 -0
- package/dist/outbound-schemas.js.map +1 -0
- package/dist/paths.d.ts +10 -0
- package/dist/paths.js +42 -0
- package/dist/paths.js.map +1 -0
- package/dist/plugin/agend/.claude-plugin/plugin.json +5 -0
- package/dist/quickstart.d.ts +1 -0
- package/dist/quickstart.js +595 -0
- package/dist/quickstart.js.map +1 -0
- package/dist/routing-engine.d.ts +22 -0
- package/dist/routing-engine.js +44 -0
- package/dist/routing-engine.js.map +1 -0
- package/dist/safe-async.d.ts +6 -0
- package/dist/safe-async.js +20 -0
- package/dist/safe-async.js.map +1 -0
- package/dist/scheduler/db.d.ts +37 -0
- package/dist/scheduler/db.js +360 -0
- package/dist/scheduler/db.js.map +1 -0
- package/dist/scheduler/db.test.d.ts +1 -0
- package/dist/scheduler/db.test.js +92 -0
- package/dist/scheduler/db.test.js.map +1 -0
- package/dist/scheduler/index.d.ts +4 -0
- package/dist/scheduler/index.js +4 -0
- package/dist/scheduler/index.js.map +1 -0
- package/dist/scheduler/scheduler.d.ts +44 -0
- package/dist/scheduler/scheduler.js +197 -0
- package/dist/scheduler/scheduler.js.map +1 -0
- package/dist/scheduler/scheduler.test.d.ts +1 -0
- package/dist/scheduler/scheduler.test.js +119 -0
- package/dist/scheduler/scheduler.test.js.map +1 -0
- package/dist/scheduler/types.d.ts +107 -0
- package/dist/scheduler/types.js +7 -0
- package/dist/scheduler/types.js.map +1 -0
- package/dist/service-installer.d.ts +17 -0
- package/dist/service-installer.js +182 -0
- package/dist/service-installer.js.map +1 -0
- package/dist/setup-wizard.d.ts +48 -0
- package/dist/setup-wizard.js +701 -0
- package/dist/setup-wizard.js.map +1 -0
- package/dist/statusline-watcher.d.ts +34 -0
- package/dist/statusline-watcher.js +73 -0
- package/dist/statusline-watcher.js.map +1 -0
- package/dist/stt.d.ts +10 -0
- package/dist/stt.js +33 -0
- package/dist/stt.js.map +1 -0
- package/dist/tmux-control.d.ts +52 -0
- package/dist/tmux-control.js +207 -0
- package/dist/tmux-control.js.map +1 -0
- package/dist/tmux-manager.d.ts +44 -0
- package/dist/tmux-manager.js +218 -0
- package/dist/tmux-manager.js.map +1 -0
- package/dist/topic-archiver.d.ts +40 -0
- package/dist/topic-archiver.js +103 -0
- package/dist/topic-archiver.js.map +1 -0
- package/dist/topic-commands.d.ts +28 -0
- package/dist/topic-commands.js +359 -0
- package/dist/topic-commands.js.map +1 -0
- package/dist/transcript-monitor.d.ts +23 -0
- package/dist/transcript-monitor.js +164 -0
- package/dist/transcript-monitor.js.map +1 -0
- package/dist/types.d.ts +211 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/ui/dashboard.html +719 -0
- package/dist/web-api.d.ts +101 -0
- package/dist/web-api.js +648 -0
- package/dist/web-api.js.map +1 -0
- package/dist/webhook-emitter.d.ts +15 -0
- package/dist/webhook-emitter.js +41 -0
- package/dist/webhook-emitter.js.map +1 -0
- package/dist/workflow-templates/default.md +35 -0
- package/package.json +76 -0
- package/templates/launchd.plist.ejs +31 -0
- package/templates/systemd.service.ejs +16 -0
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
const MAX_MESSAGE_LENGTH = 4096;
|
|
2
|
+
const WORKER_IDLE_WAIT_MS = 200;
|
|
3
|
+
const WORKER_BETWEEN_MS = 50;
|
|
4
|
+
const MAX_BACKOFF_MS = 30_000;
|
|
5
|
+
const FLOOD_CONTROL_THRESHOLD_MS = 10_000;
|
|
6
|
+
const INITIAL_BACKOFF_MS = 1_000;
|
|
7
|
+
function is429Error(err) {
|
|
8
|
+
if (err instanceof Error) {
|
|
9
|
+
const e = err;
|
|
10
|
+
if (e.status === 429)
|
|
11
|
+
return true;
|
|
12
|
+
if (e.code === 429)
|
|
13
|
+
return true;
|
|
14
|
+
if (e.response?.status === 429)
|
|
15
|
+
return true;
|
|
16
|
+
if (e.message.includes("429") || e.message.toLowerCase().includes("too many requests"))
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
function splitText(text) {
|
|
22
|
+
const chunks = [];
|
|
23
|
+
let offset = 0;
|
|
24
|
+
while (offset < text.length) {
|
|
25
|
+
chunks.push(text.slice(offset, offset + MAX_MESSAGE_LENGTH));
|
|
26
|
+
offset += MAX_MESSAGE_LENGTH;
|
|
27
|
+
}
|
|
28
|
+
return chunks;
|
|
29
|
+
}
|
|
30
|
+
export class MessageQueue {
|
|
31
|
+
sender;
|
|
32
|
+
queues = new Map();
|
|
33
|
+
stopped = true;
|
|
34
|
+
logger;
|
|
35
|
+
constructor(sender, logger) {
|
|
36
|
+
this.sender = sender;
|
|
37
|
+
this.logger = logger;
|
|
38
|
+
}
|
|
39
|
+
queueKey(chatId, threadId) {
|
|
40
|
+
return threadId != null ? `${chatId}:${threadId}` : `${chatId}:`;
|
|
41
|
+
}
|
|
42
|
+
getOrCreateQueue(chatId, threadId) {
|
|
43
|
+
const key = this.queueKey(chatId, threadId);
|
|
44
|
+
let state = this.queues.get(key);
|
|
45
|
+
if (!state) {
|
|
46
|
+
state = {
|
|
47
|
+
key: { chatId, threadId },
|
|
48
|
+
items: [],
|
|
49
|
+
backoffMs: INITIAL_BACKOFF_MS,
|
|
50
|
+
backoffUntil: 0,
|
|
51
|
+
running: false,
|
|
52
|
+
};
|
|
53
|
+
this.queues.set(key, state);
|
|
54
|
+
}
|
|
55
|
+
return state;
|
|
56
|
+
}
|
|
57
|
+
enqueue(chatId, threadId, msg) {
|
|
58
|
+
const state = this.getOrCreateQueue(chatId, threadId);
|
|
59
|
+
state.items.push(msg);
|
|
60
|
+
// If worker is already running, it will pick this up automatically.
|
|
61
|
+
// If queue was started and worker is not running, restart it.
|
|
62
|
+
if (!this.stopped && !state.running) {
|
|
63
|
+
this.runWorker(state);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
start() {
|
|
67
|
+
this.stopped = false;
|
|
68
|
+
// Start workers for any queues that already have items
|
|
69
|
+
for (const state of this.queues.values()) {
|
|
70
|
+
if (!state.running && state.items.length > 0) {
|
|
71
|
+
this.runWorker(state);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
stop() {
|
|
76
|
+
this.stopped = true;
|
|
77
|
+
// Clear all queues
|
|
78
|
+
for (const state of this.queues.values()) {
|
|
79
|
+
state.items = [];
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
async runWorker(state) {
|
|
83
|
+
if (state.running)
|
|
84
|
+
return;
|
|
85
|
+
state.running = true;
|
|
86
|
+
while (!this.stopped) {
|
|
87
|
+
// Apply backoff if needed
|
|
88
|
+
const now = Date.now();
|
|
89
|
+
if (state.backoffUntil > now) {
|
|
90
|
+
const waitMs = state.backoffUntil - now;
|
|
91
|
+
await this.sleep(Math.min(waitMs, 100));
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
// Apply flood control: drop status_update items if backoff > threshold
|
|
95
|
+
if (state.backoffMs > FLOOD_CONTROL_THRESHOLD_MS) {
|
|
96
|
+
const before = state.items.length;
|
|
97
|
+
state.items = state.items.filter(item => item.type !== "status_update");
|
|
98
|
+
if (before !== state.items.length) {
|
|
99
|
+
// Items were dropped; reset backoff so we retry the surviving
|
|
100
|
+
// (presumably more important) content sooner instead of waiting
|
|
101
|
+
// out the full exponential delay.
|
|
102
|
+
state.backoffMs = INITIAL_BACKOFF_MS;
|
|
103
|
+
state.backoffUntil = 0;
|
|
104
|
+
this.logger?.warn({ chatId: state.key.chatId, dropped: before - state.items.length }, "MessageQueue flood control: dropped status_update items, backoff reset");
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
if (state.items.length === 0) {
|
|
108
|
+
await this.sleep(WORKER_IDLE_WAIT_MS);
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
// Pop and process next item(s)
|
|
112
|
+
const { items: pendingItems, work } = this.prepareNext(state);
|
|
113
|
+
if (!work) {
|
|
114
|
+
await this.sleep(WORKER_IDLE_WAIT_MS);
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
try {
|
|
118
|
+
await work();
|
|
119
|
+
// Reset backoff on success
|
|
120
|
+
state.backoffMs = INITIAL_BACKOFF_MS;
|
|
121
|
+
state.backoffUntil = 0;
|
|
122
|
+
await this.sleep(WORKER_BETWEEN_MS);
|
|
123
|
+
}
|
|
124
|
+
catch (err) {
|
|
125
|
+
if (is429Error(err)) {
|
|
126
|
+
// Re-insert the consumed items back at the front of the queue
|
|
127
|
+
state.items.unshift(...pendingItems);
|
|
128
|
+
// Exponential backoff, cap at MAX_BACKOFF_MS
|
|
129
|
+
state.backoffUntil = Date.now() + state.backoffMs;
|
|
130
|
+
state.backoffMs = Math.min(state.backoffMs * 2, MAX_BACKOFF_MS);
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
// Non-rate-limit error: drop the item to avoid infinite loops
|
|
134
|
+
this.logger?.warn({ err, chatId: state.key.chatId }, "Message dropped due to non-retryable error");
|
|
135
|
+
state.backoffMs = INITIAL_BACKOFF_MS;
|
|
136
|
+
state.backoffUntil = 0;
|
|
137
|
+
await this.sleep(WORKER_BETWEEN_MS);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
state.running = false;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Synchronously extracts items from the queue and returns the extracted items
|
|
145
|
+
* plus an async work function. The work function does the actual sending.
|
|
146
|
+
* This split allows us to know which items to re-queue if the work fails.
|
|
147
|
+
*/
|
|
148
|
+
prepareNext(state) {
|
|
149
|
+
const { chatId, threadId } = state.key;
|
|
150
|
+
const first = state.items[0];
|
|
151
|
+
if (!first)
|
|
152
|
+
return { items: [], work: null };
|
|
153
|
+
if (first.type === "content") {
|
|
154
|
+
const { merged, consumed } = this.mergeContentMessages(state);
|
|
155
|
+
const work = async () => {
|
|
156
|
+
for (const chunk of merged) {
|
|
157
|
+
if (chunk.filePath) {
|
|
158
|
+
await this.sender.sendFile(chatId, threadId, chunk.filePath);
|
|
159
|
+
}
|
|
160
|
+
else if (chunk.text) {
|
|
161
|
+
const parts = splitText(chunk.text);
|
|
162
|
+
for (const part of parts) {
|
|
163
|
+
await this.sender.send(chatId, threadId, part);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
return { items: consumed, work };
|
|
169
|
+
}
|
|
170
|
+
else if (first.type === "status_update") {
|
|
171
|
+
state.items.shift();
|
|
172
|
+
const item = first;
|
|
173
|
+
const work = async () => {
|
|
174
|
+
if (item.editMessageId) {
|
|
175
|
+
await this.sender.edit(chatId, item.editMessageId, item.text ?? "");
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
await this.sender.send(chatId, threadId, item.text ?? "");
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
return { items: [item], work };
|
|
182
|
+
}
|
|
183
|
+
else if (first.type === "status_clear") {
|
|
184
|
+
state.items.shift();
|
|
185
|
+
return { items: [first], work: async () => { } };
|
|
186
|
+
}
|
|
187
|
+
return { items: [], work: null };
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Merges all adjacent content messages at the front of the queue.
|
|
191
|
+
* Respects the 4096 char limit per chunk.
|
|
192
|
+
* Returns merged chunks plus the original consumed items (for re-queuing on error).
|
|
193
|
+
*/
|
|
194
|
+
mergeContentMessages(state) {
|
|
195
|
+
// Collect all leading content items
|
|
196
|
+
const consumed = [];
|
|
197
|
+
while (state.items.length > 0 && state.items[0].type === "content") {
|
|
198
|
+
consumed.push(state.items.shift());
|
|
199
|
+
}
|
|
200
|
+
const merged = [];
|
|
201
|
+
let currentText = "";
|
|
202
|
+
for (const item of consumed) {
|
|
203
|
+
if (item.filePath) {
|
|
204
|
+
// Flush any pending text first
|
|
205
|
+
if (currentText.length > 0) {
|
|
206
|
+
const parts = splitText(currentText);
|
|
207
|
+
for (const part of parts) {
|
|
208
|
+
merged.push({ text: part });
|
|
209
|
+
}
|
|
210
|
+
currentText = "";
|
|
211
|
+
}
|
|
212
|
+
merged.push({ filePath: item.filePath });
|
|
213
|
+
}
|
|
214
|
+
else if (item.text) {
|
|
215
|
+
// Try to append to current text, splitting if necessary
|
|
216
|
+
const combined = currentText + item.text;
|
|
217
|
+
if (combined.length <= MAX_MESSAGE_LENGTH) {
|
|
218
|
+
currentText = combined;
|
|
219
|
+
}
|
|
220
|
+
else {
|
|
221
|
+
// Flush current accumulated text first
|
|
222
|
+
if (currentText.length > 0) {
|
|
223
|
+
const parts = splitText(currentText);
|
|
224
|
+
for (const part of parts) {
|
|
225
|
+
merged.push({ text: part });
|
|
226
|
+
}
|
|
227
|
+
currentText = "";
|
|
228
|
+
}
|
|
229
|
+
// Now handle item.text which might itself be long
|
|
230
|
+
if (item.text.length <= MAX_MESSAGE_LENGTH) {
|
|
231
|
+
currentText = item.text;
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
234
|
+
const parts = splitText(item.text);
|
|
235
|
+
const lastPart = parts.pop();
|
|
236
|
+
for (const part of parts) {
|
|
237
|
+
merged.push({ text: part });
|
|
238
|
+
}
|
|
239
|
+
currentText = lastPart;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
if (currentText.length > 0) {
|
|
245
|
+
merged.push({ text: currentText });
|
|
246
|
+
}
|
|
247
|
+
return { merged, consumed };
|
|
248
|
+
}
|
|
249
|
+
sleep(ms) {
|
|
250
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
//# sourceMappingURL=message-queue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"message-queue.js","sourceRoot":"","sources":["../../src/channel/message-queue.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ChannelAdapter } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Route a channel tool call (reply, react, edit_message, download_attachment)
|
|
4
|
+
* to the adapter. Returns true if handled, false if unknown tool.
|
|
5
|
+
*/
|
|
6
|
+
export declare function routeToolCall(adapter: ChannelAdapter, tool: string, args: Record<string, unknown>, threadId: string | undefined, respond: (result: unknown, error?: string) => void): boolean;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { resolve, sep } from "node:path";
|
|
2
|
+
import { realpathSync, existsSync } from "node:fs";
|
|
3
|
+
import { getAgendHome } from "../paths.js";
|
|
4
|
+
const STATE_DIR = resolve(getAgendHome()) + sep;
|
|
5
|
+
const INBOX_SEG = sep + "inbox" + sep;
|
|
6
|
+
/** Block files inside the state dir (except inbox/) from being sent out. */
|
|
7
|
+
function assertSendable(filePath) {
|
|
8
|
+
let resolved;
|
|
9
|
+
try {
|
|
10
|
+
resolved = realpathSync(filePath);
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
if (!existsSync(filePath))
|
|
14
|
+
return; // truly missing — let adapter handle
|
|
15
|
+
throw new Error(`Blocked: cannot resolve path ${filePath}`);
|
|
16
|
+
}
|
|
17
|
+
if (resolved.startsWith(STATE_DIR) && !resolved.includes(INBOX_SEG)) {
|
|
18
|
+
throw new Error(`Blocked: refusing to send state file ${filePath}`);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Route a channel tool call (reply, react, edit_message, download_attachment)
|
|
23
|
+
* to the adapter. Returns true if handled, false if unknown tool.
|
|
24
|
+
*/
|
|
25
|
+
export function routeToolCall(adapter, tool, args, threadId, respond) {
|
|
26
|
+
const chatId = args.chat_id ?? "";
|
|
27
|
+
switch (tool) {
|
|
28
|
+
case "reply": {
|
|
29
|
+
const files = Array.isArray(args.files) ? args.files : [];
|
|
30
|
+
if (files.length > 20) {
|
|
31
|
+
respond(null, `reply: too many files (${files.length}); max 20 per message`);
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
try {
|
|
35
|
+
for (const f of files)
|
|
36
|
+
assertSendable(f);
|
|
37
|
+
}
|
|
38
|
+
catch (e) {
|
|
39
|
+
respond(null, e.message);
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
const replyThreadId = args.thread_id ?? threadId;
|
|
43
|
+
const format = args.format === "markdown" ? "html" : undefined;
|
|
44
|
+
adapter.sendText(chatId, args.text ?? "", {
|
|
45
|
+
threadId: replyThreadId,
|
|
46
|
+
replyTo: args.reply_to,
|
|
47
|
+
format,
|
|
48
|
+
}).then(async (sent) => {
|
|
49
|
+
for (const filePath of files) {
|
|
50
|
+
await adapter.sendFile(chatId, filePath, { threadId: replyThreadId });
|
|
51
|
+
}
|
|
52
|
+
respond(sent);
|
|
53
|
+
}).catch(e => respond(null, e.message));
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
case "react":
|
|
57
|
+
adapter.react(chatId, args.message_id ?? "", args.emoji ?? "")
|
|
58
|
+
.then(() => respond("ok"))
|
|
59
|
+
.catch(e => respond(null, e.message));
|
|
60
|
+
return true;
|
|
61
|
+
case "edit_message":
|
|
62
|
+
adapter.editMessage(chatId, args.message_id ?? "", args.text ?? "")
|
|
63
|
+
.then(() => respond("ok"))
|
|
64
|
+
.catch(e => respond(null, e.message));
|
|
65
|
+
return true;
|
|
66
|
+
case "download_attachment":
|
|
67
|
+
adapter.downloadAttachment(args.file_id ?? "")
|
|
68
|
+
.then(path => respond(path))
|
|
69
|
+
.catch(e => respond(null, e.message));
|
|
70
|
+
return true;
|
|
71
|
+
default:
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=tool-router.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-router.js","sourceRoot":"","sources":["../../src/channel/tool-router.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ChannelAdapter } from "./types.js";
|
|
2
|
+
export declare class ToolTracker {
|
|
3
|
+
private adapter;
|
|
4
|
+
private chatId;
|
|
5
|
+
private threadId?;
|
|
6
|
+
private statusMessageId;
|
|
7
|
+
private lines;
|
|
8
|
+
constructor(adapter: ChannelAdapter, chatId: string, threadId?: string | undefined);
|
|
9
|
+
onToolUse(toolName: string, input: unknown): Promise<void>;
|
|
10
|
+
onToolResult(toolName: string, _output: unknown): Promise<void>;
|
|
11
|
+
reset(): void;
|
|
12
|
+
private summarizeTool;
|
|
13
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
export class ToolTracker {
|
|
2
|
+
adapter;
|
|
3
|
+
chatId;
|
|
4
|
+
threadId;
|
|
5
|
+
statusMessageId = null;
|
|
6
|
+
lines = [];
|
|
7
|
+
constructor(adapter, chatId, threadId) {
|
|
8
|
+
this.adapter = adapter;
|
|
9
|
+
this.chatId = chatId;
|
|
10
|
+
this.threadId = threadId;
|
|
11
|
+
}
|
|
12
|
+
async onToolUse(toolName, input) {
|
|
13
|
+
const summary = this.summarizeTool(toolName, input);
|
|
14
|
+
this.lines.push(`🔧 ${summary}`);
|
|
15
|
+
if (!this.statusMessageId) {
|
|
16
|
+
// First tool — send new message
|
|
17
|
+
const sent = await this.adapter.sendText(this.chatId, this.lines.join("\n"), { threadId: this.threadId });
|
|
18
|
+
this.statusMessageId = sent.messageId;
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
// Subsequent — edit existing
|
|
22
|
+
await this.adapter.editMessage(this.chatId, this.statusMessageId, this.lines.join("\n"));
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
async onToolResult(toolName, _output) {
|
|
26
|
+
// Find the last line matching this tool and mark it done
|
|
27
|
+
for (let i = this.lines.length - 1; i >= 0; i--) {
|
|
28
|
+
if (this.lines[i].includes(toolName) && this.lines[i].startsWith("🔧")) {
|
|
29
|
+
this.lines[i] = this.lines[i].replace("🔧", "✅");
|
|
30
|
+
break;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
if (this.statusMessageId) {
|
|
34
|
+
await this.adapter.editMessage(this.chatId, this.statusMessageId, this.lines.join("\n"));
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
reset() {
|
|
38
|
+
this.statusMessageId = null;
|
|
39
|
+
this.lines = [];
|
|
40
|
+
}
|
|
41
|
+
summarizeTool(name, input) {
|
|
42
|
+
const inp = input;
|
|
43
|
+
if (name === "Read")
|
|
44
|
+
return `Read: ${inp.file_path ?? ""}`;
|
|
45
|
+
if (name === "Edit")
|
|
46
|
+
return `Edit: ${inp.file_path ?? ""}`;
|
|
47
|
+
if (name === "Write")
|
|
48
|
+
return `Write: ${inp.file_path ?? ""}`;
|
|
49
|
+
if (name === "Bash")
|
|
50
|
+
return `Bash: ${String(inp.command ?? "").slice(0, 60)}`;
|
|
51
|
+
if (name === "Glob")
|
|
52
|
+
return `Glob: ${inp.pattern ?? ""}`;
|
|
53
|
+
if (name === "Grep")
|
|
54
|
+
return `Grep: ${inp.pattern ?? ""}`;
|
|
55
|
+
return name;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=tool-tracker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-tracker.js","sourceRoot":"","sources":["../../src/channel/tool-tracker.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { EventEmitter } from "node:events";
|
|
2
|
+
export interface Choice {
|
|
3
|
+
id: string;
|
|
4
|
+
label: string;
|
|
5
|
+
}
|
|
6
|
+
export interface InstanceStatusData {
|
|
7
|
+
name: string;
|
|
8
|
+
status: "running" | "stopped" | "crashed" | "paused";
|
|
9
|
+
contextPct: number | null;
|
|
10
|
+
costCents: number;
|
|
11
|
+
}
|
|
12
|
+
export interface AlertData {
|
|
13
|
+
type: "hang" | "cost_warn" | "cost_limit" | "schedule_deferred" | "rotation";
|
|
14
|
+
instanceName: string;
|
|
15
|
+
message: string;
|
|
16
|
+
choices?: Choice[];
|
|
17
|
+
}
|
|
18
|
+
export interface ChannelAdapter extends EventEmitter {
|
|
19
|
+
readonly type: string;
|
|
20
|
+
readonly id: string;
|
|
21
|
+
start(): Promise<void>;
|
|
22
|
+
stop(): Promise<void>;
|
|
23
|
+
sendText(chatId: string, text: string, opts?: SendOpts): Promise<SentMessage>;
|
|
24
|
+
sendFile(chatId: string, filePath: string, opts?: SendOpts): Promise<SentMessage>;
|
|
25
|
+
editMessage(chatId: string, messageId: string, text: string): Promise<void>;
|
|
26
|
+
react(chatId: string, messageId: string, emoji: string): Promise<void>;
|
|
27
|
+
sendApproval(prompt: PermissionPrompt, callback: (decision: "approve" | "approve_always" | "deny") => void, signal?: AbortSignal, threadId?: string): Promise<ApprovalHandle>;
|
|
28
|
+
downloadAttachment(fileId: string): Promise<string>;
|
|
29
|
+
handlePairing(chatId: string, userId: string): Promise<string>;
|
|
30
|
+
confirmPairing(code: string, callerUserId?: string): Promise<boolean>;
|
|
31
|
+
readonly topology: "topics" | "channels" | "flat";
|
|
32
|
+
setChatId(chatId: string): void;
|
|
33
|
+
getChatId(): string | null;
|
|
34
|
+
promptUser(chatId: string, text: string, choices: Choice[], opts?: SendOpts): Promise<string>;
|
|
35
|
+
notifyAlert(chatId: string, alert: AlertData, opts?: SendOpts): Promise<SentMessage>;
|
|
36
|
+
createTopic?(name: string): Promise<number | string>;
|
|
37
|
+
deleteTopic?(topicId: number | string): Promise<void>;
|
|
38
|
+
topicExists?(topicId: number | string): Promise<boolean>;
|
|
39
|
+
closeForumTopic?(threadId: number | string): Promise<void>;
|
|
40
|
+
reopenForumTopic?(threadId: number | string): Promise<void>;
|
|
41
|
+
editForumTopic?(threadId: number | string, opts: {
|
|
42
|
+
name?: string;
|
|
43
|
+
iconCustomEmojiId?: string;
|
|
44
|
+
}): Promise<void>;
|
|
45
|
+
getTopicIconStickers?(): Promise<{
|
|
46
|
+
customEmojiId: string;
|
|
47
|
+
emoji: string;
|
|
48
|
+
}[]>;
|
|
49
|
+
}
|
|
50
|
+
export interface ApprovalHandle {
|
|
51
|
+
cancel(): void;
|
|
52
|
+
}
|
|
53
|
+
export interface SendOpts {
|
|
54
|
+
threadId?: string;
|
|
55
|
+
replyTo?: string;
|
|
56
|
+
format?: "text" | "html";
|
|
57
|
+
chunkLimit?: number;
|
|
58
|
+
}
|
|
59
|
+
export interface SentMessage {
|
|
60
|
+
messageId: string;
|
|
61
|
+
chatId: string;
|
|
62
|
+
threadId?: string;
|
|
63
|
+
}
|
|
64
|
+
export interface OutboundMessage {
|
|
65
|
+
text?: string;
|
|
66
|
+
filePath?: string;
|
|
67
|
+
threadId?: string;
|
|
68
|
+
replyTo?: string;
|
|
69
|
+
format?: "text" | "html";
|
|
70
|
+
}
|
|
71
|
+
export interface InboundMessage {
|
|
72
|
+
source: string;
|
|
73
|
+
adapterId: string;
|
|
74
|
+
chatId: string;
|
|
75
|
+
threadId?: string;
|
|
76
|
+
messageId: string;
|
|
77
|
+
userId: string;
|
|
78
|
+
username: string;
|
|
79
|
+
text: string;
|
|
80
|
+
timestamp: Date;
|
|
81
|
+
isBotMessage?: boolean;
|
|
82
|
+
attachments?: Attachment[];
|
|
83
|
+
replyTo?: string;
|
|
84
|
+
replyToText?: string;
|
|
85
|
+
}
|
|
86
|
+
export interface Attachment {
|
|
87
|
+
kind: "photo" | "document" | "audio" | "voice" | "video" | "sticker";
|
|
88
|
+
fileId: string;
|
|
89
|
+
localPath?: string;
|
|
90
|
+
mime?: string;
|
|
91
|
+
size?: number;
|
|
92
|
+
filename?: string;
|
|
93
|
+
transcription?: string;
|
|
94
|
+
}
|
|
95
|
+
export interface PermissionPrompt {
|
|
96
|
+
tool_name: string;
|
|
97
|
+
description: string;
|
|
98
|
+
input_preview?: string;
|
|
99
|
+
}
|
|
100
|
+
export interface ApprovalResponse {
|
|
101
|
+
decision: "approve" | "approve_always" | "deny";
|
|
102
|
+
respondedBy?: {
|
|
103
|
+
channelType: string;
|
|
104
|
+
userId: string;
|
|
105
|
+
};
|
|
106
|
+
reason?: string;
|
|
107
|
+
}
|
|
108
|
+
export interface Target {
|
|
109
|
+
adapterId?: string;
|
|
110
|
+
chatId: string;
|
|
111
|
+
threadId?: string;
|
|
112
|
+
}
|
|
113
|
+
export interface QueuedMessage {
|
|
114
|
+
type: "content" | "status_update" | "status_clear";
|
|
115
|
+
text?: string;
|
|
116
|
+
filePath?: string;
|
|
117
|
+
editMessageId?: string;
|
|
118
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/channel/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import Database from "better-sqlite3";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
const PALETTE = [
|
|
4
|
+
"#58a6ff", "#3fb950", "#d29922", "#f85149",
|
|
5
|
+
"#bc8cff", "#79c0ff", "#56d364", "#e3b341",
|
|
6
|
+
];
|
|
7
|
+
function agentColor(name, map) {
|
|
8
|
+
if (map.has(name))
|
|
9
|
+
return map.get(name);
|
|
10
|
+
const color = PALETTE[map.size % PALETTE.length];
|
|
11
|
+
map.set(name, color);
|
|
12
|
+
return color;
|
|
13
|
+
}
|
|
14
|
+
function escapeHtml(s) {
|
|
15
|
+
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
16
|
+
}
|
|
17
|
+
export function exportChat(dbPath, opts) {
|
|
18
|
+
if (!existsSync(dbPath)) {
|
|
19
|
+
return generateHtml([], "No activity database found.");
|
|
20
|
+
}
|
|
21
|
+
const db = new Database(dbPath, { readonly: true });
|
|
22
|
+
let query = "SELECT * FROM activity";
|
|
23
|
+
const conditions = [];
|
|
24
|
+
const params = [];
|
|
25
|
+
if (opts.from) {
|
|
26
|
+
conditions.push("timestamp >= ?");
|
|
27
|
+
params.push(opts.from);
|
|
28
|
+
}
|
|
29
|
+
if (opts.to) {
|
|
30
|
+
conditions.push("timestamp <= ?");
|
|
31
|
+
params.push(opts.to);
|
|
32
|
+
}
|
|
33
|
+
if (conditions.length) {
|
|
34
|
+
query += " WHERE " + conditions.join(" AND ");
|
|
35
|
+
}
|
|
36
|
+
query += " ORDER BY timestamp ASC, id ASC";
|
|
37
|
+
const rows = db.prepare(query).all(...params);
|
|
38
|
+
db.close();
|
|
39
|
+
if (rows.length === 0) {
|
|
40
|
+
return generateHtml([], "No messages in this time range.");
|
|
41
|
+
}
|
|
42
|
+
return generateHtml(rows);
|
|
43
|
+
}
|
|
44
|
+
function generateHtml(rows, emptyMsg) {
|
|
45
|
+
const colorMap = new Map();
|
|
46
|
+
const messages = rows.map(row => {
|
|
47
|
+
const senderColor = agentColor(row.sender, colorMap);
|
|
48
|
+
const time = row.timestamp.slice(11, 16); // HH:MM
|
|
49
|
+
const date = row.timestamp.slice(0, 10);
|
|
50
|
+
const content = escapeHtml(row.summary);
|
|
51
|
+
const eventIcon = row.event === "tool_call" ? "🔧" : row.event === "task_update" ? "📋" : "";
|
|
52
|
+
const receiver = row.receiver ? ` → <span style="color:${agentColor(row.receiver, colorMap)}">${escapeHtml(row.receiver)}</span>` : "";
|
|
53
|
+
return `<div class="msg">
|
|
54
|
+
<div class="meta">
|
|
55
|
+
<span class="time">${date} ${time}</span>
|
|
56
|
+
<span class="sender" style="color:${senderColor}">${eventIcon}${escapeHtml(row.sender)}</span>${receiver}
|
|
57
|
+
</div>
|
|
58
|
+
<div class="content">${content}</div>
|
|
59
|
+
</div>`;
|
|
60
|
+
}).join("\n");
|
|
61
|
+
return `<!DOCTYPE html>
|
|
62
|
+
<html lang="en">
|
|
63
|
+
<head>
|
|
64
|
+
<meta charset="utf-8">
|
|
65
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
66
|
+
<title>AgEnD Chat Export</title>
|
|
67
|
+
<style>
|
|
68
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
69
|
+
body { background: #0d1117; color: #c9d1d9; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', monospace; padding: 16px; max-width: 900px; margin: 0 auto; }
|
|
70
|
+
h1 { font-size: 18px; color: #58a6ff; padding: 12px 0; border-bottom: 1px solid #21262d; margin-bottom: 16px; }
|
|
71
|
+
.empty { color: #8b949e; padding: 24px; text-align: center; }
|
|
72
|
+
.msg { padding: 8px 12px; margin: 4px 0; border-radius: 6px; background: #161b22; border-left: 3px solid #30363d; }
|
|
73
|
+
.meta { font-size: 12px; margin-bottom: 4px; }
|
|
74
|
+
.time { color: #8b949e; margin-right: 8px; }
|
|
75
|
+
.sender { font-weight: 600; }
|
|
76
|
+
.content { font-size: 14px; line-height: 1.5; white-space: pre-wrap; word-break: break-word; }
|
|
77
|
+
.legend { display: flex; gap: 16px; flex-wrap: wrap; padding: 8px 0; margin-bottom: 12px; font-size: 12px; }
|
|
78
|
+
.legend-item { display: flex; align-items: center; gap: 4px; }
|
|
79
|
+
.legend-dot { width: 10px; height: 10px; border-radius: 50%; }
|
|
80
|
+
</style>
|
|
81
|
+
</head>
|
|
82
|
+
<body>
|
|
83
|
+
<h1>AgEnD Chat Export</h1>
|
|
84
|
+
${emptyMsg ? `<div class="empty">${escapeHtml(emptyMsg)}</div>` : ""}
|
|
85
|
+
${rows.length > 0 ? `<div class="legend">${[...colorMap.entries()].map(([name, color]) => `<div class="legend-item"><div class="legend-dot" style="background:${color}"></div>${escapeHtml(name)}</div>`).join("")}</div>` : ""}
|
|
86
|
+
${messages}
|
|
87
|
+
<div style="color:#8b949e;font-size:11px;padding:16px 0;text-align:center;">Generated by AgEnD · ${rows.length} messages · ${new Date().toISOString().slice(0, 19)}</div>
|
|
88
|
+
</body>
|
|
89
|
+
</html>`;
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=chat-export.js.map
|