MCPcopy Create free account
hub / github.com/QodeXcli/QodeX / runSubagent

Method runSubagent

src/agent/loop.ts:276–364  ·  view source on GitHub ↗

* Run a sub-agent inline. Used by the `task` tool. * * Architecture: sub-agent gets a fresh AgentLoop with the same router/registry/perms * but a new session id and an isolated message history. Tools run in 'subagent' mode * (task and present_plan filtered). We drain the event stream and

(
    prompt: string,
    opts: {
      maxIterations: number;
      signal?: AbortSignal;
      sessionId: string;
      modelOverride?: string;
      /** Role name — drives model selection, system prompt, tool restriction. Default 'subagent'. */
      role?: string;
    },
  )

Source from the content-addressed store, hash-verified

274 (this.config as any).safety = { ...(this.config as any).safety, autoSnapshot: enabled };
275 }
276
277 /**
278 * Queue a mid-task steering note (from `/btw …`). Picked up at the top of the next
279 * run-loop iteration and injected into the conversation. Safe to call while a run
280 * is in flight; no-ops on an empty/whitespace note.
281 */
282 pushSteer(note: string): void {
283 if (typeof note === 'string' && note.trim().length > 0) {
284 this.steerQueue.push(note.trim());
285 }
286 }
287
288 /** True when there are steering notes waiting to be injected. */
289 hasPendingSteer(): boolean {
290 return this.steerQueue.length > 0;
291 }
292
293 /**
294 * Run a sub-agent inline. Used by the `task` tool.
295 *
296 * Architecture: sub-agent gets a fresh AgentLoop with the same router/registry/perms
297 * but a new session id and an isolated message history. Tools run in 'subagent' mode
298 * (task and present_plan filtered). We drain the event stream and collect just the
299 * final text + tool-call count.
300 *
301 * The sub-agent's events ARE persisted to the session store under its sub-session id —
302 * so `qx sessions` will list it as a child, debuggable independently. We do NOT
303 * pipe sub-agent UI events to the parent's UI; the parent just sees the eventual
304 * tool result.
305 */
306 async runSubagent(
307 prompt: string,
308 opts: {
309 maxIterations: number;
310 signal?: AbortSignal;
311 sessionId: string;
312 modelOverride?: string;
313 /** Role name — drives model selection, system prompt, tool restriction. Default 'subagent'. */
314 role?: string;
315 },
316 ): Promise<{ finalText: string; toolCallsRun: number; ok: boolean; error?: string; modelUsed?: string }> {
317 let finalText = '';
318 let toolCallsRun = 0;
319 let errMsg: string | undefined;
320 let ok = true;
321 let modelUsed: string | undefined;
322 try {
323 const role = opts.role ?? 'subagent';
324 // Resolve which model this sub-agent should use, applying the precedence rules:
325 // explicit (opts.modelOverride) > session override > config.roles.<role> > config.roles.subagent > parent default.
326 const resolved = resolveRole(role, this.config, opts.modelOverride);
327
328 // ── Token-efficiency auto-offload (opt-in, offload.enabled) ──
329 // A scout dispatch is read-only recon whose output only the PARENT consumes — the
330 // safe set for a cheap model. Only lift the model when nothing more specific chose
331 // one (source parent-default): explicit per-call overrides, session overrides and
332 // config roles always win. Follow-up: extend to other read-only roles once the
333 // policy has mileage. Non-scout roles are untouched by design (see offload-policy.ts).

Callers 1

AppFunction · 0.95

Calls 4

buildInitialMessagesMethod · 0.95
runMethod · 0.95
resolveRoleFunction · 0.85
infoMethod · 0.80

Tested by

no test coverage detected