Darochin's picture
Mirror OpenSkyNet workspace snapshot from Git HEAD
fc93158 verified
import { resolveStoredSubagentCapabilities } from "../../../agents/subagent-capabilities.js";
import type { ResolvedSubagentController } from "../../../agents/subagent-control.js";
import {
countPendingDescendantRuns,
type SubagentRunRecord,
} from "../../../agents/subagent-registry.js";
import {
extractAssistantText,
resolveInternalSessionKey,
resolveMainSessionAlias,
sanitizeTextContent,
stripToolMessages,
} from "../../../agents/tools/sessions-helpers.js";
import type {
SessionEntry,
loadSessionStore as loadSessionStoreFn,
resolveStorePath as resolveStorePathFn,
} from "../../../config/sessions.js";
import { parseDiscordTarget } from "../../../discord/targets.js";
import { callGateway } from "../../../gateway/call.js";
import { formatTimeAgo } from "../../../infra/format-time/format-relative.ts";
import { parseAgentSessionKey } from "../../../routing/session-key.js";
import { isSubagentSessionKey } from "../../../routing/session-key.js";
import { looksLikeSessionId } from "../../../sessions/session-id.js";
import { extractTextFromChatContent } from "../../../shared/chat-content.js";
import {
formatDurationCompact,
formatTokenUsageDisplay,
truncateLine,
} from "../../../shared/subagents-format.js";
import {
isDiscordSurface,
isTelegramSurface,
resolveCommandSurfaceChannel,
resolveDiscordAccountId,
resolveChannelAccountId,
} from "../channel-context.js";
import type { CommandHandler, CommandHandlerResult } from "../commands-types.js";
import {
formatRunLabel,
formatRunStatus,
resolveSubagentTargetFromRuns,
type SubagentTargetResolution,
} from "../subagents-utils.js";
import { resolveTelegramConversationId } from "../telegram-context.js";
export { extractAssistantText, stripToolMessages };
export {
isDiscordSurface,
isTelegramSurface,
resolveCommandSurfaceChannel,
resolveDiscordAccountId,
resolveChannelAccountId,
resolveTelegramConversationId,
};
export const COMMAND = "/subagents";
export const COMMAND_KILL = "/kill";
export const COMMAND_STEER = "/steer";
export const COMMAND_TELL = "/tell";
export const COMMAND_FOCUS = "/focus";
export const COMMAND_UNFOCUS = "/unfocus";
export const COMMAND_AGENTS = "/agents";
export const ACTIONS = new Set([
"list",
"kill",
"log",
"send",
"steer",
"info",
"spawn",
"focus",
"unfocus",
"agents",
"help",
]);
export const RECENT_WINDOW_MINUTES = 30;
const SUBAGENT_TASK_PREVIEW_MAX = 110;
export const STEER_ABORT_SETTLE_TIMEOUT_MS = 5_000;
function compactLine(value: string) {
return value.replace(/\s+/g, " ").trim();
}
function formatTaskPreview(value: string) {
return truncateLine(compactLine(value), SUBAGENT_TASK_PREVIEW_MAX);
}
function resolveModelDisplay(
entry?: {
model?: unknown;
modelProvider?: unknown;
modelOverride?: unknown;
providerOverride?: unknown;
},
fallbackModel?: string,
) {
const model = typeof entry?.model === "string" ? entry.model.trim() : "";
const provider = typeof entry?.modelProvider === "string" ? entry.modelProvider.trim() : "";
let combined = model.includes("/") ? model : model && provider ? `${provider}/${model}` : model;
if (!combined) {
const overrideModel =
typeof entry?.modelOverride === "string" ? entry.modelOverride.trim() : "";
const overrideProvider =
typeof entry?.providerOverride === "string" ? entry.providerOverride.trim() : "";
combined = overrideModel.includes("/")
? overrideModel
: overrideModel && overrideProvider
? `${overrideProvider}/${overrideModel}`
: overrideModel;
}
if (!combined) {
combined = fallbackModel?.trim() || "";
}
if (!combined) {
return "model n/a";
}
const slash = combined.lastIndexOf("/");
if (slash >= 0 && slash < combined.length - 1) {
return combined.slice(slash + 1);
}
return combined;
}
export function resolveDisplayStatus(
entry: SubagentRunRecord,
options?: { pendingDescendants?: number },
) {
const pendingDescendants = Math.max(0, options?.pendingDescendants ?? 0);
if (pendingDescendants > 0) {
const childLabel = pendingDescendants === 1 ? "child" : "children";
return `active (waiting on ${pendingDescendants} ${childLabel})`;
}
const status = formatRunStatus(entry);
return status === "error" ? "failed" : status;
}
export function formatSubagentListLine(params: {
entry: SubagentRunRecord;
index: number;
runtimeMs: number;
sessionEntry?: SessionEntry;
pendingDescendants?: number;
}) {
const usageText = formatTokenUsageDisplay(params.sessionEntry);
const label = truncateLine(formatRunLabel(params.entry, { maxLength: 48 }), 48);
const task = formatTaskPreview(params.entry.task);
const runtime = formatDurationCompact(params.runtimeMs);
const status = resolveDisplayStatus(params.entry, {
pendingDescendants: params.pendingDescendants,
});
return `${params.index}. ${label} (${resolveModelDisplay(params.sessionEntry, params.entry.model)}, ${runtime}${usageText ? `, ${usageText}` : ""}) ${status}${task.toLowerCase() !== label.toLowerCase() ? ` - ${task}` : ""}`;
}
function formatTimestamp(valueMs?: number) {
if (!valueMs || !Number.isFinite(valueMs) || valueMs <= 0) {
return "n/a";
}
return new Date(valueMs).toISOString();
}
export function formatTimestampWithAge(valueMs?: number) {
if (!valueMs || !Number.isFinite(valueMs) || valueMs <= 0) {
return "n/a";
}
return `${formatTimestamp(valueMs)} (${formatTimeAgo(Date.now() - valueMs, { fallback: "n/a" })})`;
}
export type SubagentsAction =
| "list"
| "kill"
| "log"
| "send"
| "steer"
| "info"
| "spawn"
| "focus"
| "unfocus"
| "agents"
| "help";
export type SubagentsCommandParams = Parameters<CommandHandler>[0];
export type SubagentsCommandContext = {
params: SubagentsCommandParams;
handledPrefix: string;
requesterKey: string;
runs: SubagentRunRecord[];
restTokens: string[];
};
export function stopWithText(text: string): CommandHandlerResult {
return { shouldContinue: false, reply: { text } };
}
export function stopWithUnknownTargetError(error?: string): CommandHandlerResult {
return stopWithText(`⚠️ ${error ?? "Unknown subagent."}`);
}
export function resolveSubagentTarget(
runs: SubagentRunRecord[],
token: string | undefined,
): SubagentTargetResolution {
return resolveSubagentTargetFromRuns({
runs,
token,
recentWindowMinutes: RECENT_WINDOW_MINUTES,
label: (entry) => formatRunLabel(entry),
isActive: (entry) =>
!entry.endedAt || Math.max(0, countPendingDescendantRuns(entry.childSessionKey)) > 0,
errors: {
missingTarget: "Missing subagent id.",
invalidIndex: (value) => `Invalid subagent index: ${value}`,
unknownSession: (value) => `Unknown subagent session: ${value}`,
ambiguousLabel: (value) => `Ambiguous subagent label: ${value}`,
ambiguousLabelPrefix: (value) => `Ambiguous subagent label prefix: ${value}`,
ambiguousRunIdPrefix: (value) => `Ambiguous run id prefix: ${value}`,
unknownTarget: (value) => `Unknown subagent id: ${value}`,
},
});
}
export function resolveSubagentEntryForToken(
runs: SubagentRunRecord[],
token: string | undefined,
): { entry: SubagentRunRecord } | { reply: CommandHandlerResult } {
const resolved = resolveSubagentTarget(runs, token);
if (!resolved.entry) {
return { reply: stopWithUnknownTargetError(resolved.error) };
}
return { entry: resolved.entry };
}
export function resolveRequesterSessionKey(
params: SubagentsCommandParams,
opts?: { preferCommandTarget?: boolean },
): string | undefined {
const commandTarget = params.ctx.CommandTargetSessionKey?.trim();
const commandSession = params.sessionKey?.trim();
const shouldPreferCommandTarget =
opts?.preferCommandTarget ?? params.ctx.CommandSource === "native";
const raw = shouldPreferCommandTarget
? commandTarget || commandSession
: commandSession || commandTarget;
if (!raw) {
return undefined;
}
const { mainKey, alias } = resolveMainSessionAlias(params.cfg);
return resolveInternalSessionKey({ key: raw, alias, mainKey });
}
export function resolveCommandSubagentController(
params: SubagentsCommandParams,
requesterKey: string,
): ResolvedSubagentController {
if (!isSubagentSessionKey(requesterKey)) {
return {
controllerSessionKey: requesterKey,
callerSessionKey: requesterKey,
callerIsSubagent: false,
controlScope: "children",
};
}
const capabilities = resolveStoredSubagentCapabilities(requesterKey, {
cfg: params.cfg,
});
return {
controllerSessionKey: requesterKey,
callerSessionKey: requesterKey,
callerIsSubagent: true,
controlScope: capabilities.controlScope,
};
}
export function resolveHandledPrefix(normalized: string): string | null {
return normalized.startsWith(COMMAND)
? COMMAND
: normalized.startsWith(COMMAND_KILL)
? COMMAND_KILL
: normalized.startsWith(COMMAND_STEER)
? COMMAND_STEER
: normalized.startsWith(COMMAND_TELL)
? COMMAND_TELL
: normalized.startsWith(COMMAND_FOCUS)
? COMMAND_FOCUS
: normalized.startsWith(COMMAND_UNFOCUS)
? COMMAND_UNFOCUS
: normalized.startsWith(COMMAND_AGENTS)
? COMMAND_AGENTS
: null;
}
export function resolveSubagentsAction(params: {
handledPrefix: string;
restTokens: string[];
}): SubagentsAction | null {
if (params.handledPrefix === COMMAND) {
const [actionRaw] = params.restTokens;
const action = (actionRaw?.toLowerCase() || "list") as SubagentsAction;
if (!ACTIONS.has(action)) {
return null;
}
params.restTokens.splice(0, 1);
return action;
}
if (params.handledPrefix === COMMAND_KILL) {
return "kill";
}
if (params.handledPrefix === COMMAND_FOCUS) {
return "focus";
}
if (params.handledPrefix === COMMAND_UNFOCUS) {
return "unfocus";
}
if (params.handledPrefix === COMMAND_AGENTS) {
return "agents";
}
return "steer";
}
export type FocusTargetResolution = {
targetKind: "subagent" | "acp";
targetSessionKey: string;
agentId: string;
label?: string;
};
export function resolveDiscordChannelIdForFocus(
params: SubagentsCommandParams,
): string | undefined {
const toCandidates = [
typeof params.ctx.OriginatingTo === "string" ? params.ctx.OriginatingTo.trim() : "",
typeof params.command.to === "string" ? params.command.to.trim() : "",
typeof params.ctx.To === "string" ? params.ctx.To.trim() : "",
].filter(Boolean);
for (const candidate of toCandidates) {
try {
const target = parseDiscordTarget(candidate, { defaultKind: "channel" });
if (target?.kind === "channel" && target.id) {
return target.id;
}
} catch {
// Ignore parse failures and try the next candidate.
}
}
return undefined;
}
export async function resolveFocusTargetSession(params: {
runs: SubagentRunRecord[];
token: string;
}): Promise<FocusTargetResolution | null> {
const subagentMatch = resolveSubagentTarget(params.runs, params.token);
if (subagentMatch.entry) {
const key = subagentMatch.entry.childSessionKey;
const parsed = parseAgentSessionKey(key);
return {
targetKind: "subagent",
targetSessionKey: key,
agentId: parsed?.agentId ?? "main",
label: formatRunLabel(subagentMatch.entry),
};
}
const token = params.token.trim();
if (!token) {
return null;
}
const attempts: Array<Record<string, string>> = [];
attempts.push({ key: token });
if (looksLikeSessionId(token)) {
attempts.push({ sessionId: token });
}
attempts.push({ label: token });
for (const attempt of attempts) {
try {
const resolved = await callGateway<{ key?: string }>({
method: "sessions.resolve",
params: attempt,
});
const key = typeof resolved?.key === "string" ? resolved.key.trim() : "";
if (!key) {
continue;
}
const parsed = parseAgentSessionKey(key);
return {
targetKind: key.includes(":subagent:") ? "subagent" : "acp",
targetSessionKey: key,
agentId: parsed?.agentId ?? "main",
label: token,
};
} catch {
// Try the next resolution strategy.
}
}
return null;
}
export function buildSubagentsHelp() {
return [
"Subagents",
"Usage:",
"- /subagents list",
"- /subagents kill <id|#|all>",
"- /subagents log <id|#> [limit] [tools]",
"- /subagents info <id|#>",
"- /subagents send <id|#> <message>",
"- /subagents steer <id|#> <message>",
"- /subagents spawn <agentId> <task> [--model <model>] [--thinking <level>]",
"- /focus <subagent-label|session-key|session-id|session-label>",
"- /unfocus",
"- /agents",
"- /session idle <duration|off>",
"- /session max-age <duration|off>",
"- /kill <id|#|all>",
"- /steer <id|#> <message>",
"- /tell <id|#> <message>",
"",
"Ids: use the list index (#), runId/session prefix, label, or full session key.",
].join("\n");
}
export type ChatMessage = {
role?: unknown;
content?: unknown;
};
export function extractMessageText(message: ChatMessage): { role: string; text: string } | null {
const role = typeof message.role === "string" ? message.role : "";
const shouldSanitize = role === "assistant";
const text = extractTextFromChatContent(message.content, {
sanitizeText: shouldSanitize ? sanitizeTextContent : undefined,
});
return text ? { role, text } : null;
}
export function formatLogLines(messages: ChatMessage[]) {
const lines: string[] = [];
for (const msg of messages) {
const extracted = extractMessageText(msg);
if (!extracted) {
continue;
}
const label = extracted.role === "assistant" ? "Assistant" : "User";
lines.push(`${label}: ${extracted.text}`);
}
return lines;
}
export type SessionStoreCache = Map<string, Record<string, SessionEntry>>;
export function loadSubagentSessionEntry(
params: SubagentsCommandParams,
childKey: string,
loaders: {
loadSessionStore: typeof loadSessionStoreFn;
resolveStorePath: typeof resolveStorePathFn;
},
storeCache?: SessionStoreCache,
) {
const parsed = parseAgentSessionKey(childKey);
const storePath = loaders.resolveStorePath(params.cfg.session?.store, {
agentId: parsed?.agentId,
});
let store = storeCache?.get(storePath);
if (!store) {
store = loaders.loadSessionStore(storePath);
storeCache?.set(storePath, store);
}
return { storePath, store, entry: store[childKey] };
}