fix: Add 'running' field to sessions_list for accurate subagent status

sessions_list was reporting totalTokens: 0 for actively running subagent
sessions because token counts are only persisted at run completion.

This caused orchestration logic to incorrectly determine agent availability.

Changes:
- Add getRunningSubagentSessions() to subagent-registry.ts
- Add isSubagentSessionRunning() helper for individual checks
- Modify listSessionsFromStore() to include 'running' field
- Update GatewaySessionRow and SessionListRow types

The 'running' field is true when a session has an active subagent run
(startedAt is set but endedAt is not).

Fixes: #2129
This commit is contained in:
Nick DiMoro 2026-01-26 01:05:44 -07:00
parent 9eafc6a9f0
commit a35d319580
5 changed files with 40 additions and 0 deletions

View File

@ -369,3 +369,32 @@ export function listSubagentRunsForRequester(requesterSessionKey: string): Subag
export function initSubagentRegistry() {
restoreSubagentRunsOnce();
}
/**
* Check if a session key has an active (in-progress) subagent run.
* Returns true if a run exists with startedAt but no endedAt.
*/
export function isSubagentSessionRunning(childSessionKey: string): boolean {
const key = childSessionKey.trim();
if (!key) return false;
for (const entry of subagentRuns.values()) {
if (entry.childSessionKey === key && entry.startedAt && !entry.endedAt) {
return true;
}
}
return false;
}
/**
* Get all currently running subagent session keys.
* Returns a Set of session keys that have active runs.
*/
export function getRunningSubagentSessions(): Set<string> {
const running = new Set<string>();
for (const entry of subagentRuns.values()) {
if (entry.startedAt && !entry.endedAt) {
running.add(entry.childSessionKey);
}
}
return running;
}

View File

@ -28,6 +28,8 @@ export type SessionListRow = {
model?: string;
contextTokens?: number | null;
totalTokens?: number | null;
/** True if this session has an active subagent run in progress */
running?: boolean;
thinkingLevel?: string;
verboseLevel?: string;
systemSent?: boolean;

View File

@ -169,6 +169,7 @@ export function createSessionsListTool(opts?: {
model: typeof entry.model === "string" ? entry.model : undefined,
contextTokens: typeof entry.contextTokens === "number" ? entry.contextTokens : undefined,
totalTokens: typeof entry.totalTokens === "number" ? entry.totalTokens : undefined,
running: typeof entry.running === "boolean" ? entry.running : undefined,
thinkingLevel: typeof entry.thinkingLevel === "string" ? entry.thinkingLevel : undefined,
verboseLevel: typeof entry.verboseLevel === "string" ? entry.verboseLevel : undefined,
systemSent: typeof entry.systemSent === "boolean" ? entry.systemSent : undefined,

View File

@ -2,6 +2,7 @@ import fs from "node:fs";
import path from "node:path";
import { resolveAgentWorkspaceDir, resolveDefaultAgentId } from "../agents/agent-scope.js";
import { getRunningSubagentSessions } from "../agents/subagent-registry.js";
import { lookupContextTokens } from "../agents/context.js";
import { DEFAULT_CONTEXT_TOKENS, DEFAULT_MODEL, DEFAULT_PROVIDER } from "../agents/defaults.js";
import { resolveConfiguredModelRef } from "../agents/model-selection.js";
@ -468,6 +469,9 @@ export function listSessionsFromStore(params: {
const { cfg, storePath, store, opts } = params;
const now = Date.now();
// Get set of currently running subagent sessions for accurate status reporting
const runningSubagents = getRunningSubagentSessions();
const includeGlobal = opts.includeGlobal === true;
const includeUnknown = opts.includeUnknown === true;
const includeDerivedTitles = opts.includeDerivedTitles === true;
@ -554,6 +558,8 @@ export function listSessionsFromStore(params: {
inputTokens: entry?.inputTokens,
outputTokens: entry?.outputTokens,
totalTokens: total,
// Check if this is a running subagent (has active run but may not have tokens yet)
running: runningSubagents.has(key),
responseUsage: entry?.responseUsage,
modelProvider: entry?.modelProvider,
model: entry?.model,

View File

@ -33,6 +33,8 @@ export type GatewaySessionRow = {
inputTokens?: number;
outputTokens?: number;
totalTokens?: number;
/** True if this session has an active subagent run in progress */
running?: boolean;
responseUsage?: "on" | "off" | "tokens" | "full";
modelProvider?: string;
model?: string;