diff --git a/CHANGELOG.md b/CHANGELOG.md index 2f8d3da..a7b5f59 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -432,7 +432,7 @@ All notable changes to `@inceptionstack/roundhouse` are documented here. ### Added - Gateway with Telegram adapter, per-thread agent sessions -- `/new`, `/restart`, `/status`, `/compact`, `/verbose`, `/stop`, `/doctor` commands +- `/new`, `/restart`, `/status`, `/compact`, `/verbose`, `/cancel`, `/doctor` commands - Auto-register bot commands with Telegram on startup - Draining/drain_complete notification system - Context token usage with progress bar diff --git a/README.md b/README.md index bb24158..e53060f 100644 --- a/README.md +++ b/README.md @@ -217,7 +217,7 @@ Roundhouse automatically registers these commands with Telegram on startup: | `/compact` | Compact session context to free up tokens | | `/verbose` | Toggle tool status messages on/off for this chat | | `/status` | Show gateway status: version, agent, model, context usage, uptime, etc. | -| `/stop` | Stop the current agent run (abort tools, LLM calls, compaction) | +| `/cancel` | Stop the current agent run (abort tools, LLM calls, compaction) | | `/restart` | Restart the gateway service (requires `allowedUsers` to be configured) | | `/doctor` | Run health checks and show system status | | `/crons` | Manage scheduled jobs (list, trigger, pause, resume) | @@ -242,7 +242,7 @@ Manually triggers context compaction for the current chat's session. Shows befor Toggles verbose mode for the current chat. When ON, shows tool call status messages (e.g. "⚡ Running `bash`…"). When OFF (default), tool calls execute silently — you only see the agent's text responses. State shown in `/status`. -### `/stop` +### `/cancel` Aborts the current agent run for this chat — stops any in-progress tool calls, LLM generation, and compaction. The session is preserved; send another message to continue the conversation. diff --git a/docs/refactoring-plan.md b/docs/refactoring-plan.md index 224d16e..e83f9e0 100644 --- a/docs/refactoring-plan.md +++ b/docs/refactoring-plan.md @@ -84,7 +84,7 @@ | 4.7 | *Run tests* | Green bar | | 4.8 | *Extract Module: notifications* | Move `notifyStartup`, `postWithFallback`, `registerBotCommands` → `src/gateway/notifications.ts` | | 4.9 | *Run tests* | Green bar | -| 4.10 | *Extract Module: command-router* | Move Telegram command handlers (`/status`, `/compact`, `/update`, `/crons`, `/stop`, `/verbose`, `/doctor`) → `src/gateway/command-router.ts` as a handler map | +| 4.10 | *Extract Module: command-router* | Move Telegram command handlers (`/status`, `/compact`, `/update`, `/crons`, `/cancel`, `/verbose`, `/doctor`) → `src/gateway/command-router.ts` as a handler map | | 4.11 | *Run tests* | Green bar | | 4.12 | *Thin Gateway class* | `Gateway` becomes orchestrator importing from sub-modules (~100 lines) | | 4.13 | *Move file* | Rename `src/gateway.ts` → `src/gateway/index.ts`, update imports | diff --git a/docs/transport-adapter-design.md b/docs/transport-adapter-design.md index 2917519..bff11f4 100644 --- a/docs/transport-adapter-design.md +++ b/docs/transport-adapter-design.md @@ -66,7 +66,7 @@ export interface TransportAdapter { - Agent adapter lifecycle (create, prompt, stream) - Thread queue / concurrency management - Memory system (flush, compact, pressure) -- Command routing (/new, /stop, /status, etc.) +- Command routing (/new, /cancel, /status, etc.) - Config loading - Allowed user authorization diff --git a/src/gateway/commands.ts b/src/gateway/commands.ts index 5473936..fd37716 100644 --- a/src/gateway/commands.ts +++ b/src/gateway/commands.ts @@ -284,25 +284,25 @@ export async function handleStatus(ctx: CommandContext): Promise { console.log(`[roundhouse] /status for thread=${thread.id} agentThread=${agentThreadId}`); } -// ── /stop ──────────────────────────────────────────── +// ── /cancel ──────────────────────────────────────────── -export interface StopContext { +export interface CancelContext { thread: any; agentThreadId: string; agent: AgentAdapter; abortControllers: Map; } -export async function handleStop(ctx: StopContext): Promise { +export async function handleCancel(ctx: CancelContext): Promise { const { thread, agentThreadId, agent, abortControllers } = ctx; if (agent.abort) { await agent.abort(agentThreadId); abortControllers.get(agentThreadId)?.abort(); - try { await thread.post("⏹️ Stopped."); } catch {} + try { await thread.post("⏹️ Cancelled."); } catch {} } else { try { await thread.post("⚠️ Abort not supported for this agent."); } catch {} } - console.log(`[roundhouse] /stop for thread=${thread.id} agentThread=${agentThreadId}`); + console.log(`[roundhouse] /cancel for thread=${thread.id} agentThread=${agentThreadId}`); } // ── /verbose ───────────────────────────────────────── diff --git a/src/gateway/gateway.ts b/src/gateway/gateway.ts index 54a16a0..587d405 100644 --- a/src/gateway/gateway.ts +++ b/src/gateway/gateway.ts @@ -22,7 +22,7 @@ import type { PressureLevel } from "../memory/types"; import { isCommand as _isCmd, isCommandWithArgs as _isCmdArgs, resolveAgentThreadId as _resolveThread, getSystemResources as _getSysRes } from "./helpers"; import { saveAttachments, type AttachmentResult } from "./attachments"; import { handleStreaming as _handleStream, StreamModelOverflowError } from "./streaming"; -import { handleNew, handleRestart, handleUpdate, handleCompact, handleStatus, handleStop, handleVerbose, handleDoctor, handleCrons, type CommandContext } from "./commands"; +import { handleNew, handleRestart, handleUpdate, handleCompact, handleStatus, handleCancel, handleVerbose, handleDoctor, handleCrons, type CommandContext } from "./commands"; import { handleModel, handleModelAction, MODEL_ACTION_ID } from "./model-command"; import { handleLater } from "./later-command"; import { handleTopic, handleTopicAction, TOPIC_ACTION_ID, applyTopicOverride } from "./topic-command"; @@ -209,10 +209,10 @@ export class Gateway { // Per-thread verbose toggle (shows tool_start messages) const verboseThreads = this.verboseThreads; - // Per-thread abort signal for /stop + // Per-thread abort signal for /cancel const abortControllers = this.abortControllers; - // Per-thread lock to serialize prompts (concurrent mode lets /stop through) + // Per-thread lock to serialize prompts (concurrent mode lets /cancel through) const threadLocks = this.threadLocks; // ── Build command descriptors ────────────────────── @@ -271,7 +271,7 @@ export class Gateway { const text = (message.text ?? "").trim(); // Pre-turn commands fire before the main handler (and before the - // session-pressure gate), so /stop etc. still interrupt a mid-run + // session-pressure gate), so /cancel etc. still interrupt a mid-run // agent. Allowlist is enforced here for all pre-turn handlers. for (const desc of preTurnCommands) { if (matchesDescriptor(desc, text, matchers)) { @@ -387,7 +387,7 @@ export class Gateway { const agent = this.router.resolve(agentThreadId); - // Serialize prompts per-thread (concurrent mode allows /stop to bypass) + // Serialize prompts per-thread (concurrent mode allows /cancel to bypass) const prevLock = threadLocks.get(agentThreadId); let releaseLock: () => void; const lockPromise = new Promise((resolve) => { releaseLock = resolve; }); @@ -750,7 +750,7 @@ export class Gateway { * * Stage: * - "in-turn" (default): runs after allowlist + pairing inside handle() - * - "pre-turn": runs first in handleOrAbort() so commands like /stop + * - "pre-turn": runs first in handleOrAbort() so commands like /cancel * can interrupt an in-flight agent turn * * Per-request state (thread, message, text) comes in via CommandInvocation; @@ -813,9 +813,9 @@ export class Gateway { // ── Pre-turn commands (abort-style; fire even during agent turn) ── { - triggers: ["/stop"], + triggers: ["/cancel"], stage: "pre-turn", - invoke: ({ thread, agentThreadId }) => handleStop({ + invoke: ({ thread, agentThreadId }) => handleCancel({ thread, agentThreadId, agent: this.router.resolve(agentThreadId), abortControllers, diff --git a/src/transports/telegram/bot-commands.ts b/src/transports/telegram/bot-commands.ts index 965eb71..9cdb69c 100644 --- a/src/transports/telegram/bot-commands.ts +++ b/src/transports/telegram/bot-commands.ts @@ -17,7 +17,7 @@ export const BOT_COMMANDS: BotCommand[] = [ { command: "later", description: "Save an idea for later" }, { command: "topic", description: "Switch conversation topic" }, { command: "verbose", description: "Toggle verbose tool output" }, - { command: "stop", description: "Stop the current agent run" }, + { command: "cancel", description: "Cancel the current agent run" }, { command: "restart", description: "Restart agent process" }, { command: "update", description: "Update roundhouse and restart" }, { command: "status", description: "Show system status" }, diff --git a/test/gateway-helpers.test.ts b/test/gateway-helpers.test.ts index 97fc652..d14ac25 100644 --- a/test/gateway-helpers.test.ts +++ b/test/gateway-helpers.test.ts @@ -24,7 +24,7 @@ describe("gateway/helpers", () => { }); it("rejects non-matching command", () => { - expect(isCommand("/stop", "/start", "mybot")).toBe(false); + expect(isCommand("/cancel", "/start", "mybot")).toBe(false); }); });