@visorcraft/idlehands 1.1.7 → 1.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +46 -0
- package/dist/agent/formatting.js +273 -0
- package/dist/agent/formatting.js.map +1 -0
- package/dist/agent/review-artifact.js +147 -0
- package/dist/agent/review-artifact.js.map +1 -0
- package/dist/agent/tool-calls.js +411 -0
- package/dist/agent/tool-calls.js.map +1 -0
- package/dist/agent.js +285 -684
- package/dist/agent.js.map +1 -1
- package/dist/anton/controller.js +1 -1
- package/dist/anton/controller.js.map +1 -1
- package/dist/anton/lock.js +0 -3
- package/dist/anton/lock.js.map +1 -1
- package/dist/anton/parser.js +6 -6
- package/dist/anton/parser.js.map +1 -1
- package/dist/anton/reporter.js +1 -1
- package/dist/anton/reporter.js.map +1 -1
- package/dist/bot/commands.js +3 -2
- package/dist/bot/commands.js.map +1 -1
- package/dist/bot/confirm-telegram.js +2 -1
- package/dist/bot/confirm-telegram.js.map +1 -1
- package/dist/bot/discord-routing.js +186 -0
- package/dist/bot/discord-routing.js.map +1 -0
- package/dist/bot/discord-streaming.js +107 -0
- package/dist/bot/discord-streaming.js.map +1 -0
- package/dist/bot/discord.js +49 -237
- package/dist/bot/discord.js.map +1 -1
- package/dist/bot/format.js +2 -25
- package/dist/bot/format.js.map +1 -1
- package/dist/bot/session-manager.js +22 -11
- package/dist/bot/session-manager.js.map +1 -1
- package/dist/bot/telegram.js +83 -94
- package/dist/bot/telegram.js.map +1 -1
- package/dist/cli/build-repl-context.js.map +1 -1
- package/dist/cli/command-registry.js +2 -1
- package/dist/cli/command-registry.js.map +1 -1
- package/dist/cli/command-utils.js +27 -0
- package/dist/cli/command-utils.js.map +1 -0
- package/dist/cli/commands/anton.js +3 -2
- package/dist/cli/commands/anton.js.map +1 -1
- package/dist/cli/commands/model.js +8 -7
- package/dist/cli/commands/model.js.map +1 -1
- package/dist/cli/commands/project.js +5 -4
- package/dist/cli/commands/project.js.map +1 -1
- package/dist/cli/commands/session.js +9 -8
- package/dist/cli/commands/session.js.map +1 -1
- package/dist/cli/commands/tools.js +4 -3
- package/dist/cli/commands/tools.js.map +1 -1
- package/dist/cli/input.js +2 -1
- package/dist/cli/input.js.map +1 -1
- package/dist/cli/repl-dispatch.js +85 -0
- package/dist/cli/repl-dispatch.js.map +1 -0
- package/dist/cli/runtime-cmds.js +148 -20
- package/dist/cli/runtime-cmds.js.map +1 -1
- package/dist/cli/service.js +0 -14
- package/dist/cli/service.js.map +1 -1
- package/dist/cli/setup.js +3 -3
- package/dist/cli/setup.js.map +1 -1
- package/dist/cli/watch.js +2 -1
- package/dist/cli/watch.js.map +1 -1
- package/dist/client.js +24 -7
- package/dist/client.js.map +1 -1
- package/dist/context.js +101 -10
- package/dist/context.js.map +1 -1
- package/dist/harnesses.js +1 -1
- package/dist/harnesses.js.map +1 -1
- package/dist/hooks/manager.js +5 -0
- package/dist/hooks/manager.js.map +1 -1
- package/dist/index.js +13 -64
- package/dist/index.js.map +1 -1
- package/dist/progress/agent-hooks.js +37 -0
- package/dist/progress/agent-hooks.js.map +1 -0
- package/dist/progress/ir.js +10 -0
- package/dist/progress/ir.js.map +1 -0
- package/dist/progress/message-edit-scheduler.js +97 -0
- package/dist/progress/message-edit-scheduler.js.map +1 -0
- package/dist/progress/progress-message-renderer.js +120 -0
- package/dist/progress/progress-message-renderer.js.map +1 -0
- package/dist/progress/progress-presenter.js +137 -0
- package/dist/progress/progress-presenter.js.map +1 -0
- package/dist/progress/serialize-discord.js +72 -0
- package/dist/progress/serialize-discord.js.map +1 -0
- package/dist/progress/serialize-telegram.js +67 -0
- package/dist/progress/serialize-telegram.js.map +1 -0
- package/dist/progress/serialize-tui.js +52 -0
- package/dist/progress/serialize-tui.js.map +1 -0
- package/dist/progress/tool-summary.js +58 -0
- package/dist/progress/tool-summary.js.map +1 -0
- package/dist/progress/tool-tail.js +48 -0
- package/dist/progress/tool-tail.js.map +1 -0
- package/dist/progress/turn-progress.js +215 -0
- package/dist/progress/turn-progress.js.map +1 -0
- package/dist/replay.js +2 -5
- package/dist/replay.js.map +1 -1
- package/dist/runtime/executor.js +58 -10
- package/dist/runtime/executor.js.map +1 -1
- package/dist/runtime/planner.js +19 -6
- package/dist/runtime/planner.js.map +1 -1
- package/dist/runtime/store.js +2 -1
- package/dist/runtime/store.js.map +1 -1
- package/dist/safety.js +0 -1
- package/dist/safety.js.map +1 -1
- package/dist/spinner.js +8 -0
- package/dist/spinner.js.map +1 -1
- package/dist/tools/tool-error.js +97 -0
- package/dist/tools/tool-error.js.map +1 -0
- package/dist/tools.js +471 -41
- package/dist/tools.js.map +1 -1
- package/dist/tui/branch-picker.js.map +1 -1
- package/dist/tui/command-handler.js.map +1 -1
- package/dist/tui/controller.js +91 -28
- package/dist/tui/controller.js.map +1 -1
- package/dist/tui/render.js +15 -2
- package/dist/tui/render.js.map +1 -1
- package/dist/tui/state.js +13 -0
- package/dist/tui/state.js.map +1 -1
- package/dist/upgrade.js.map +1 -1
- package/dist/utils.js +17 -0
- package/dist/utils.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discord-routing.js","sourceRoot":"","sources":["../../src/bot/discord-routing.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { splitDiscord, safeContent } from './discord-routing.js';
|
|
2
|
+
import { formatToolCallSummary } from '../progress/tool-summary.js';
|
|
3
|
+
import { ProgressPresenter } from '../progress/progress-presenter.js';
|
|
4
|
+
import { MessageEditScheduler, classifyDiscordEditError } from '../progress/message-edit-scheduler.js';
|
|
5
|
+
export class DiscordStreamingMessage {
|
|
6
|
+
placeholder;
|
|
7
|
+
channel;
|
|
8
|
+
opts;
|
|
9
|
+
banner = null;
|
|
10
|
+
finalized = false;
|
|
11
|
+
presenter = new ProgressPresenter({
|
|
12
|
+
maxToolLines: 8,
|
|
13
|
+
maxTailLines: 4,
|
|
14
|
+
maxDiffLines: 32,
|
|
15
|
+
maxAssistantChars: 1200,
|
|
16
|
+
discordMaxLen: 1900,
|
|
17
|
+
toolCallSummary: (c) => formatToolCallSummary({ name: c.name, args: c.args }),
|
|
18
|
+
});
|
|
19
|
+
scheduler = null;
|
|
20
|
+
constructor(placeholder, channel, opts) {
|
|
21
|
+
this.placeholder = placeholder;
|
|
22
|
+
this.channel = channel;
|
|
23
|
+
this.opts = opts;
|
|
24
|
+
}
|
|
25
|
+
start() {
|
|
26
|
+
if (this.scheduler || this.finalized)
|
|
27
|
+
return;
|
|
28
|
+
this.presenter.start();
|
|
29
|
+
if (this.placeholder) {
|
|
30
|
+
const every = Math.max(500, Math.floor(this.opts?.editIntervalMs ?? 1500));
|
|
31
|
+
this.scheduler = new MessageEditScheduler({
|
|
32
|
+
intervalMs: every,
|
|
33
|
+
render: () => this.presenter.renderDiscordMarkdown(),
|
|
34
|
+
apply: async (text) => {
|
|
35
|
+
if (!this.placeholder)
|
|
36
|
+
return;
|
|
37
|
+
await this.placeholder.edit(text);
|
|
38
|
+
},
|
|
39
|
+
isDirty: () => this.presenter.isDirty(),
|
|
40
|
+
clearDirty: () => this.presenter.clearDirty(),
|
|
41
|
+
classifyError: classifyDiscordEditError,
|
|
42
|
+
});
|
|
43
|
+
this.scheduler.start();
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
stop() {
|
|
47
|
+
if (this.scheduler) {
|
|
48
|
+
this.scheduler.stop();
|
|
49
|
+
this.scheduler = null;
|
|
50
|
+
}
|
|
51
|
+
this.presenter.stop();
|
|
52
|
+
}
|
|
53
|
+
setBanner(text) {
|
|
54
|
+
this.banner = text?.trim() ? text.trim() : null;
|
|
55
|
+
this.presenter.setBanner(this.banner);
|
|
56
|
+
}
|
|
57
|
+
hooks() {
|
|
58
|
+
return this.presenter.hooks();
|
|
59
|
+
}
|
|
60
|
+
async finalize(finalText) {
|
|
61
|
+
this.finalized = true;
|
|
62
|
+
this.stop();
|
|
63
|
+
const snap = this.presenter.snapshot('stop');
|
|
64
|
+
const toolLines = snap.toolLines.slice(-8);
|
|
65
|
+
// Build combined text with informative fallback
|
|
66
|
+
let combined = '';
|
|
67
|
+
if (toolLines.length)
|
|
68
|
+
combined += toolLines.join('\n') + '\n\n';
|
|
69
|
+
if (finalText && finalText.trim()) {
|
|
70
|
+
combined += finalText;
|
|
71
|
+
}
|
|
72
|
+
else if (finalText) {
|
|
73
|
+
combined += '*(response contained only protocol artifacts - no user-visible content)*';
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
combined += '*(no response generated - task may be complete or awaiting further input)*';
|
|
77
|
+
}
|
|
78
|
+
const chunks = splitDiscord(safeContent(combined));
|
|
79
|
+
if (this.placeholder && chunks.length > 0) {
|
|
80
|
+
await this.placeholder.edit(chunks[0]).catch(() => { });
|
|
81
|
+
}
|
|
82
|
+
else if (chunks.length > 0) {
|
|
83
|
+
await this.channel.send(chunks[0]).catch(() => { });
|
|
84
|
+
}
|
|
85
|
+
for (let i = 1; i < chunks.length && i < 10; i++) {
|
|
86
|
+
await this.channel.send(chunks[i]).catch(() => { });
|
|
87
|
+
}
|
|
88
|
+
if (chunks.length > 10) {
|
|
89
|
+
await this.channel.send('[truncated — response too long]').catch(() => { });
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
async finalizeError(errMsg) {
|
|
93
|
+
this.finalized = true;
|
|
94
|
+
this.stop();
|
|
95
|
+
const snap = this.presenter.snapshot('stop');
|
|
96
|
+
const toolLines = snap.toolLines.slice(-8);
|
|
97
|
+
const combined = safeContent((toolLines.length ? toolLines.join('\n') + '\n\n' : '') + `❌ ${errMsg}`);
|
|
98
|
+
const chunks = splitDiscord(combined);
|
|
99
|
+
if (this.placeholder && chunks.length > 0) {
|
|
100
|
+
await this.placeholder.edit(chunks[0]).catch(() => { });
|
|
101
|
+
}
|
|
102
|
+
else if (chunks.length > 0) {
|
|
103
|
+
await this.channel.send(chunks[0]).catch(() => { });
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=discord-streaming.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discord-streaming.js","sourceRoot":"","sources":["../../src/bot/discord-streaming.ts"],"names":[],"mappings":"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"}
|
package/dist/bot/discord.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { Client, Events, GatewayIntentBits, Partials, REST, Routes, SlashCommandBuilder, } from 'discord.js';
|
|
2
2
|
import { createSession } from '../agent.js';
|
|
3
3
|
import { DiscordConfirmProvider } from './confirm-discord.js';
|
|
4
|
-
import {
|
|
4
|
+
import { parseAllowedUsers, normalizeApprovalMode, splitDiscord, safeContent, detectEscalation, checkKeywordEscalation, resolveAgentForMessage, sessionKeyForMessage, } from './discord-routing.js';
|
|
5
|
+
import { firstToken } from '../cli/command-utils.js';
|
|
5
6
|
import { projectDir } from '../utils.js';
|
|
6
7
|
import { WATCHDOG_RECOMMENDED_TUNING_TEXT, formatWatchdogCancelMessage, resolveWatchdogSettings, shouldRecommendWatchdogTuning } from '../watchdog.js';
|
|
7
8
|
import path from 'node:path';
|
|
@@ -9,183 +10,8 @@ import fs from 'node:fs/promises';
|
|
|
9
10
|
import { runAnton } from '../anton/controller.js';
|
|
10
11
|
import { parseTaskFile } from '../anton/parser.js';
|
|
11
12
|
import { formatRunSummary, formatProgressBar, formatTaskStart, formatTaskEnd, formatTaskSkip } from '../anton/reporter.js';
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
if (fromEnv && fromEnv.trim()) {
|
|
15
|
-
return new Set(fromEnv
|
|
16
|
-
.split(',')
|
|
17
|
-
.map((s) => s.trim())
|
|
18
|
-
.filter(Boolean));
|
|
19
|
-
}
|
|
20
|
-
const values = Array.isArray(cfg.allowed_users) ? cfg.allowed_users : [];
|
|
21
|
-
return new Set(values.map((v) => String(v).trim()).filter(Boolean));
|
|
22
|
-
}
|
|
23
|
-
function normalizeApprovalMode(mode, fallback) {
|
|
24
|
-
const m = String(mode ?? '').trim().toLowerCase();
|
|
25
|
-
if (m === 'plan' || m === 'default' || m === 'auto-edit' || m === 'yolo')
|
|
26
|
-
return m;
|
|
27
|
-
return fallback;
|
|
28
|
-
}
|
|
29
|
-
function splitDiscord(text, limit = 1900) {
|
|
30
|
-
if (text.length <= limit)
|
|
31
|
-
return [text];
|
|
32
|
-
const chunks = [];
|
|
33
|
-
let i = 0;
|
|
34
|
-
while (i < text.length) {
|
|
35
|
-
chunks.push(text.slice(i, i + limit));
|
|
36
|
-
i += limit;
|
|
37
|
-
}
|
|
38
|
-
return chunks;
|
|
39
|
-
}
|
|
40
|
-
function safeContent(text) {
|
|
41
|
-
const t = sanitizeBotOutputText(text).trim();
|
|
42
|
-
return t.length ? t : '(empty response)';
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* Check if the model response contains an escalation request.
|
|
46
|
-
* Returns { escalate: true, reason: string } if escalation marker found at start of response.
|
|
47
|
-
*/
|
|
48
|
-
function detectEscalation(text) {
|
|
49
|
-
const trimmed = text.trim();
|
|
50
|
-
const match = trimmed.match(/^\[ESCALATE:\s*([^\]]+)\]/i);
|
|
51
|
-
if (match) {
|
|
52
|
-
return { escalate: true, reason: match[1].trim() };
|
|
53
|
-
}
|
|
54
|
-
return { escalate: false };
|
|
55
|
-
}
|
|
56
|
-
/** Keyword presets for common escalation triggers */
|
|
57
|
-
const KEYWORD_PRESETS = {
|
|
58
|
-
coding: ['build', 'implement', 'create', 'develop', 'architect', 'refactor', 'debug', 'fix', 'code', 'program', 'write'],
|
|
59
|
-
planning: ['plan', 'design', 'roadmap', 'strategy', 'analyze', 'research', 'evaluate', 'compare'],
|
|
60
|
-
complex: ['full', 'complete', 'comprehensive', 'multi-step', 'integrate', 'migration', 'overhaul', 'entire', 'whole'],
|
|
61
|
-
};
|
|
62
|
-
/**
|
|
63
|
-
* Check if text matches a set of keywords.
|
|
64
|
-
* Returns matched keywords or empty array if none match.
|
|
65
|
-
*/
|
|
66
|
-
function matchKeywords(text, keywords, presets) {
|
|
67
|
-
const allKeywords = [...keywords];
|
|
68
|
-
// Add preset keywords
|
|
69
|
-
if (presets) {
|
|
70
|
-
for (const preset of presets) {
|
|
71
|
-
const presetWords = KEYWORD_PRESETS[preset];
|
|
72
|
-
if (presetWords)
|
|
73
|
-
allKeywords.push(...presetWords);
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
if (allKeywords.length === 0)
|
|
77
|
-
return [];
|
|
78
|
-
const lowerText = text.toLowerCase();
|
|
79
|
-
const matched = [];
|
|
80
|
-
for (const kw of allKeywords) {
|
|
81
|
-
if (kw.startsWith('re:')) {
|
|
82
|
-
// Regex pattern
|
|
83
|
-
try {
|
|
84
|
-
const regex = new RegExp(kw.slice(3), 'i');
|
|
85
|
-
if (regex.test(text))
|
|
86
|
-
matched.push(kw);
|
|
87
|
-
}
|
|
88
|
-
catch {
|
|
89
|
-
// Invalid regex, skip
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
else {
|
|
93
|
-
// Word boundary match (case-insensitive)
|
|
94
|
-
const wordRegex = new RegExp(`\\b${kw.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\b`, 'i');
|
|
95
|
-
if (wordRegex.test(lowerText))
|
|
96
|
-
matched.push(kw);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
return matched;
|
|
100
|
-
}
|
|
101
|
-
/**
|
|
102
|
-
* Check if user message matches keyword escalation triggers.
|
|
103
|
-
* Returns { escalate: true, tier: number, reason: string } if keywords match.
|
|
104
|
-
* Tier indicates which model index to escalate to (highest matching tier wins).
|
|
105
|
-
*/
|
|
106
|
-
function checkKeywordEscalation(text, escalation) {
|
|
107
|
-
if (!escalation)
|
|
108
|
-
return { escalate: false };
|
|
109
|
-
// Tiered keyword escalation
|
|
110
|
-
if (escalation.tiers && escalation.tiers.length > 0) {
|
|
111
|
-
let highestTier = -1;
|
|
112
|
-
let highestReason = '';
|
|
113
|
-
// Check each tier, highest matching tier wins
|
|
114
|
-
for (let i = 0; i < escalation.tiers.length; i++) {
|
|
115
|
-
const tier = escalation.tiers[i];
|
|
116
|
-
const matched = matchKeywords(text, tier.keywords || [], tier.keyword_presets);
|
|
117
|
-
if (matched.length > 0 && i > highestTier) {
|
|
118
|
-
highestTier = i;
|
|
119
|
-
highestReason = `tier ${i} keyword match: ${matched.slice(0, 3).join(', ')}${matched.length > 3 ? '...' : ''}`;
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
if (highestTier >= 0) {
|
|
123
|
-
return { escalate: true, tier: highestTier, reason: highestReason };
|
|
124
|
-
}
|
|
125
|
-
return { escalate: false };
|
|
126
|
-
}
|
|
127
|
-
// Legacy flat keywords (treated as tier 0)
|
|
128
|
-
const matched = matchKeywords(text, escalation.keywords || [], escalation.keyword_presets);
|
|
129
|
-
if (matched.length > 0) {
|
|
130
|
-
return {
|
|
131
|
-
escalate: true,
|
|
132
|
-
tier: 0,
|
|
133
|
-
reason: `keyword match: ${matched.slice(0, 3).join(', ')}${matched.length > 3 ? '...' : ''}`
|
|
134
|
-
};
|
|
135
|
-
}
|
|
136
|
-
return { escalate: false };
|
|
137
|
-
}
|
|
138
|
-
/**
|
|
139
|
-
* Resolve which agent persona should handle a message.
|
|
140
|
-
* Priority: user > channel > guild > default > first agent > null
|
|
141
|
-
*/
|
|
142
|
-
function resolveAgentForMessage(msg, agents, routing) {
|
|
143
|
-
const agentMap = agents ?? {};
|
|
144
|
-
const agentIds = Object.keys(agentMap);
|
|
145
|
-
// No agents configured — return null persona (use global config)
|
|
146
|
-
if (agentIds.length === 0) {
|
|
147
|
-
return { agentId: '_default', persona: null };
|
|
148
|
-
}
|
|
149
|
-
const route = routing ?? {};
|
|
150
|
-
let resolvedId;
|
|
151
|
-
// Priority 1: User-specific routing
|
|
152
|
-
if (route.users && route.users[msg.author.id]) {
|
|
153
|
-
resolvedId = route.users[msg.author.id];
|
|
154
|
-
}
|
|
155
|
-
// Priority 2: Channel-specific routing
|
|
156
|
-
else if (route.channels && route.channels[msg.channelId]) {
|
|
157
|
-
resolvedId = route.channels[msg.channelId];
|
|
158
|
-
}
|
|
159
|
-
// Priority 3: Guild-specific routing
|
|
160
|
-
else if (msg.guildId && route.guilds && route.guilds[msg.guildId]) {
|
|
161
|
-
resolvedId = route.guilds[msg.guildId];
|
|
162
|
-
}
|
|
163
|
-
// Priority 4: Default agent
|
|
164
|
-
else if (route.default) {
|
|
165
|
-
resolvedId = route.default;
|
|
166
|
-
}
|
|
167
|
-
// Priority 5: First defined agent
|
|
168
|
-
else {
|
|
169
|
-
resolvedId = agentIds[0];
|
|
170
|
-
}
|
|
171
|
-
// Validate the resolved agent exists
|
|
172
|
-
const persona = agentMap[resolvedId];
|
|
173
|
-
if (!persona) {
|
|
174
|
-
// Fallback to first agent if routing points to non-existent agent
|
|
175
|
-
const fallbackId = agentIds[0];
|
|
176
|
-
return { agentId: fallbackId, persona: agentMap[fallbackId] ?? null };
|
|
177
|
-
}
|
|
178
|
-
return { agentId: resolvedId, persona };
|
|
179
|
-
}
|
|
180
|
-
function sessionKeyForMessage(msg, allowGuilds, agentId) {
|
|
181
|
-
// Include agentId in session key so switching agents creates a new session
|
|
182
|
-
if (allowGuilds) {
|
|
183
|
-
// Per-agent+channel+user session in guilds
|
|
184
|
-
return `${agentId}:${msg.channelId}:${msg.author.id}`;
|
|
185
|
-
}
|
|
186
|
-
// DM-only mode: per-agent+user session
|
|
187
|
-
return `${agentId}:${msg.author.id}`;
|
|
188
|
-
}
|
|
13
|
+
import { DiscordStreamingMessage } from './discord-streaming.js';
|
|
14
|
+
import { chainAgentHooks } from '../progress/agent-hooks.js';
|
|
189
15
|
export async function startDiscordBot(config, botConfig) {
|
|
190
16
|
const token = process.env.IDLEHANDS_DISCORD_TOKEN || botConfig.token;
|
|
191
17
|
if (!token) {
|
|
@@ -395,20 +221,31 @@ When you escalate, your request will be re-run on a more capable model.`;
|
|
|
395
221
|
managed.lastActivity = Date.now();
|
|
396
222
|
}
|
|
397
223
|
function cancelActive(managed) {
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
try {
|
|
403
|
-
managed.activeAbortController?.abort();
|
|
224
|
+
const wasRunning = managed.inFlight;
|
|
225
|
+
const queueSize = managed.pendingQueue.length;
|
|
226
|
+
if (!wasRunning && queueSize === 0) {
|
|
227
|
+
return { ok: false, message: 'Nothing to cancel.' };
|
|
404
228
|
}
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
229
|
+
// Always clear queued work.
|
|
230
|
+
managed.pendingQueue = [];
|
|
231
|
+
if (wasRunning) {
|
|
232
|
+
managed.state = 'canceling';
|
|
233
|
+
try {
|
|
234
|
+
managed.activeAbortController?.abort();
|
|
235
|
+
}
|
|
236
|
+
catch { }
|
|
237
|
+
try {
|
|
238
|
+
managed.session.cancel();
|
|
239
|
+
}
|
|
240
|
+
catch { }
|
|
408
241
|
}
|
|
409
|
-
catch { }
|
|
410
242
|
managed.lastActivity = Date.now();
|
|
411
|
-
|
|
243
|
+
const parts = [];
|
|
244
|
+
if (wasRunning)
|
|
245
|
+
parts.push('stopping current task');
|
|
246
|
+
if (queueSize > 0)
|
|
247
|
+
parts.push(`cleared ${queueSize} queued task${queueSize > 1 ? 's' : ''}`);
|
|
248
|
+
return { ok: true, message: `⏹ Cancelled: ${parts.join(', ')}.` };
|
|
412
249
|
}
|
|
413
250
|
async function processMessage(managed, msg) {
|
|
414
251
|
let turn = beginTurn(managed);
|
|
@@ -489,14 +326,14 @@ When you escalate, your request will be re-run on a more capable model.`;
|
|
|
489
326
|
}
|
|
490
327
|
}
|
|
491
328
|
const placeholder = await sendUserVisible(msg, '⏳ Thinking...').catch(() => null);
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
329
|
+
const streamer = new DiscordStreamingMessage(placeholder, msg.channel, { editIntervalMs: 1500 });
|
|
330
|
+
streamer.start();
|
|
331
|
+
const baseHooks = {
|
|
332
|
+
onToken: () => {
|
|
495
333
|
if (!isTurnActive(managed, turnId))
|
|
496
334
|
return;
|
|
497
335
|
markProgress(managed, turnId);
|
|
498
336
|
watchdogGraceUsed = 0;
|
|
499
|
-
streamed += t;
|
|
500
337
|
},
|
|
501
338
|
onToolCall: () => {
|
|
502
339
|
if (!isTurnActive(managed, turnId))
|
|
@@ -504,6 +341,12 @@ When you escalate, your request will be re-run on a more capable model.`;
|
|
|
504
341
|
markProgress(managed, turnId);
|
|
505
342
|
watchdogGraceUsed = 0;
|
|
506
343
|
},
|
|
344
|
+
onToolStream: () => {
|
|
345
|
+
if (!isTurnActive(managed, turnId))
|
|
346
|
+
return;
|
|
347
|
+
markProgress(managed, turnId);
|
|
348
|
+
watchdogGraceUsed = 0;
|
|
349
|
+
},
|
|
507
350
|
onToolResult: () => {
|
|
508
351
|
if (!isTurnActive(managed, turnId))
|
|
509
352
|
return;
|
|
@@ -530,9 +373,7 @@ When you escalate, your request will be re-run on a more capable model.`;
|
|
|
530
373
|
watchdogGraceUsed += 1;
|
|
531
374
|
managed.lastProgressAt = Date.now();
|
|
532
375
|
console.error(`[bot:discord] ${managed.userId} watchdog inactivity on turn ${turnId} — applying grace period (${watchdogGraceUsed}/${watchdogIdleGraceTimeouts})`);
|
|
533
|
-
|
|
534
|
-
void placeholder.edit('⏳ Still working... model is taking longer than usual.').catch(() => { });
|
|
535
|
-
}
|
|
376
|
+
streamer.setBanner('⏳ Still working... model is taking longer than usual.');
|
|
536
377
|
return;
|
|
537
378
|
}
|
|
538
379
|
if (managed.watchdogCompactAttempts < maxWatchdogCompacts) {
|
|
@@ -568,17 +409,17 @@ When you escalate, your request will be re-run on a more capable model.`;
|
|
|
568
409
|
const attemptController = new AbortController();
|
|
569
410
|
managed.activeAbortController = attemptController;
|
|
570
411
|
turn.controller = attemptController;
|
|
571
|
-
streamed = '';
|
|
572
412
|
const askText = isRetryAfterCompaction
|
|
573
413
|
? 'Continue working on the task from where you left off. Context was compacted to free memory — do NOT restart from the beginning.'
|
|
574
414
|
: msg.content;
|
|
415
|
+
const hooks = chainAgentHooks({ signal: attemptController.signal }, baseHooks, streamer.hooks());
|
|
575
416
|
try {
|
|
576
|
-
const result = await managed.session.ask(askText,
|
|
417
|
+
const result = await managed.session.ask(askText, hooks);
|
|
577
418
|
askComplete = true;
|
|
578
419
|
if (!isTurnActive(managed, turnId))
|
|
579
420
|
return;
|
|
580
421
|
markProgress(managed, turnId);
|
|
581
|
-
const finalText = safeContent(
|
|
422
|
+
const finalText = safeContent(result.text);
|
|
582
423
|
// Check for auto-escalation request in response
|
|
583
424
|
const escalation = managed.agentPersona?.escalation;
|
|
584
425
|
const autoEscalate = escalation?.auto !== false && escalation?.models?.length;
|
|
@@ -592,10 +433,7 @@ When you escalate, your request will be re-run on a more capable model.`;
|
|
|
592
433
|
// Get endpoint from tier if defined
|
|
593
434
|
const tierEndpoint = escalation.tiers?.[nextIndex]?.endpoint;
|
|
594
435
|
console.error(`[bot:discord] ${managed.userId} auto-escalation requested: ${escResult.reason}${tierEndpoint ? ` @ ${tierEndpoint}` : ''}`);
|
|
595
|
-
|
|
596
|
-
if (placeholder) {
|
|
597
|
-
await placeholder.edit(`⚡ Escalating to \`${targetModel}\` (${escResult.reason})...`).catch(() => { });
|
|
598
|
-
}
|
|
436
|
+
await streamer.finalizeError(`⚡ Escalating to \`${targetModel}\` (${escResult.reason})...`);
|
|
599
437
|
// Set up escalation for re-run
|
|
600
438
|
managed.pendingEscalation = targetModel;
|
|
601
439
|
managed.currentModelIndex = nextIndex + 1;
|
|
@@ -615,30 +453,14 @@ When you escalate, your request will be re-run on a more capable model.`;
|
|
|
615
453
|
return;
|
|
616
454
|
}
|
|
617
455
|
}
|
|
618
|
-
|
|
619
|
-
if (placeholder) {
|
|
620
|
-
await placeholder.edit(chunks[0]).catch(() => { });
|
|
621
|
-
}
|
|
622
|
-
else {
|
|
623
|
-
await sendUserVisible(msg, chunks[0]).catch(() => { });
|
|
624
|
-
}
|
|
625
|
-
for (let i = 1; i < chunks.length && i < 10; i++) {
|
|
626
|
-
if (!isTurnActive(managed, turnId))
|
|
627
|
-
break;
|
|
628
|
-
await msg.channel.send(chunks[i]).catch(() => { });
|
|
629
|
-
}
|
|
630
|
-
if (chunks.length > 10 && isTurnActive(managed, turnId)) {
|
|
631
|
-
await msg.channel.send('[truncated — response too long]').catch(() => { });
|
|
632
|
-
}
|
|
456
|
+
await streamer.finalize(finalText);
|
|
633
457
|
}
|
|
634
458
|
catch (e) {
|
|
635
459
|
const raw = String(e?.message ?? e ?? 'unknown error');
|
|
636
460
|
const isAbort = raw.includes('AbortError') || raw.toLowerCase().includes('aborted');
|
|
637
461
|
// If aborted by watchdog compaction, wait for compaction to finish then retry
|
|
638
462
|
if (isAbort && watchdogCompactPending) {
|
|
639
|
-
|
|
640
|
-
await placeholder.edit(`🔄 Context too large — compacting and retrying (attempt ${managed.watchdogCompactAttempts}/${maxWatchdogCompacts})...`).catch(() => { });
|
|
641
|
-
}
|
|
463
|
+
streamer.setBanner(`🔄 Context too large — compacting and retrying (attempt ${managed.watchdogCompactAttempts}/${maxWatchdogCompacts})...`);
|
|
642
464
|
// Wait for the async compaction to complete
|
|
643
465
|
while (watchdogCompactPending) {
|
|
644
466
|
await new Promise((r) => setTimeout(r, 500));
|
|
@@ -658,19 +480,11 @@ When you escalate, your request will be re-run on a more capable model.`;
|
|
|
658
480
|
abortReason: raw,
|
|
659
481
|
prefix: '⏹ ',
|
|
660
482
|
});
|
|
661
|
-
|
|
662
|
-
await placeholder.edit(cancelMsg).catch(() => { });
|
|
663
|
-
else
|
|
664
|
-
await sendUserVisible(msg, cancelMsg).catch(() => { });
|
|
483
|
+
await streamer.finalizeError(cancelMsg);
|
|
665
484
|
}
|
|
666
485
|
else {
|
|
667
486
|
const errMsg = raw.slice(0, 400);
|
|
668
|
-
|
|
669
|
-
await placeholder.edit(`❌ ${errMsg}`).catch(() => { });
|
|
670
|
-
}
|
|
671
|
-
else {
|
|
672
|
-
await sendUserVisible(msg, `❌ ${errMsg}`).catch(() => { });
|
|
673
|
-
}
|
|
487
|
+
await streamer.finalizeError(errMsg);
|
|
674
488
|
}
|
|
675
489
|
askComplete = true;
|
|
676
490
|
}
|
|
@@ -678,6 +492,7 @@ When you escalate, your request will be re-run on a more capable model.`;
|
|
|
678
492
|
}
|
|
679
493
|
finally {
|
|
680
494
|
clearInterval(watchdog);
|
|
495
|
+
streamer.stop();
|
|
681
496
|
finishTurn(managed, turnId);
|
|
682
497
|
// Auto-deescalate back to base model after each request
|
|
683
498
|
if (managed.currentModelIndex > 0 && managed.agentPersona?.escalation) {
|
|
@@ -902,12 +717,9 @@ When you escalate, your request will be re-run on a more capable model.`;
|
|
|
902
717
|
if (!managed) {
|
|
903
718
|
await interaction.reply('No active session.');
|
|
904
719
|
}
|
|
905
|
-
else if (managed.state !== 'running') {
|
|
906
|
-
await interaction.reply('Nothing to cancel.');
|
|
907
|
-
}
|
|
908
720
|
else {
|
|
909
|
-
cancelActive(managed);
|
|
910
|
-
await interaction.reply(
|
|
721
|
+
const res = cancelActive(managed);
|
|
722
|
+
await interaction.reply(res.message);
|
|
911
723
|
}
|
|
912
724
|
break;
|
|
913
725
|
}
|
|
@@ -1539,7 +1351,7 @@ When you escalate, your request will be re-run on a more capable model.`;
|
|
|
1539
1351
|
const DISCORD_RATE_LIMIT_MS = 15_000;
|
|
1540
1352
|
async function handleDiscordAnton(managed, msg, content) {
|
|
1541
1353
|
const args = content.replace(/^\/anton\s*/, '').trim();
|
|
1542
|
-
const sub = args
|
|
1354
|
+
const sub = firstToken(args);
|
|
1543
1355
|
if (!sub || sub === 'status') {
|
|
1544
1356
|
if (!managed.antonActive) {
|
|
1545
1357
|
await sendUserVisible(msg, 'No Anton run in progress.').catch(() => { });
|