refactor(core): move background injection wiring from UI to backend

Wire ExecutionLifecycleService.setInjectionService() in Config constructor
so backgrounded executions inject directly via settleExecution instead of
routing through a useEffect bridge in AppContainer.
This commit is contained in:
Adam Weidman
2026-03-15 15:11:13 -04:00
parent 931b80206b
commit 8b7321ea8d
3 changed files with 23 additions and 24 deletions
+2
View File
@@ -148,6 +148,7 @@ import type { AgentDefinition } from '../agents/types.js';
import { fetchAdminControls } from '../code_assist/admin/admin_controls.js';
import { isSubpath, resolveToRealPath } from '../utils/paths.js';
import { InjectionService } from './injectionService.js';
import { ExecutionLifecycleService } from '../services/executionLifecycleService.js';
import { WORKSPACE_POLICY_TIER } from '../policy/config.js';
import { loadPoliciesFromToml } from '../policy/toml-loader.js';
@@ -938,6 +939,7 @@ export class Config implements McpContext, AgentLoopContext {
this.injectionService = new InjectionService(() =>
this.isModelSteeringEnabled(),
);
ExecutionLifecycleService.setInjectionService(this.injectionService);
this.toolOutputMasking = {
enabled: params.toolOutputMasking?.enabled ?? true,
toolProtectionThreshold:
@@ -4,6 +4,7 @@
* SPDX-License-Identifier: Apache-2.0
*/
import type { InjectionService } from '../config/injectionService.js';
import type { AnsiOutput } from '../utils/terminalSerializer.js';
export type ExecutionMethod =
@@ -138,6 +139,15 @@ export class ExecutionLifecycleService {
>();
private static backgroundCompletionListeners =
new Set<BackgroundCompletionListener>();
private static injectionService: InjectionService | null = null;
/**
* Wires a singleton InjectionService so that backgrounded executions
* can inject their output directly without routing through the UI layer.
*/
static setInjectionService(service: InjectionService): void {
this.injectionService = service;
}
/**
* Registers a listener that fires when a previously-backgrounded
@@ -210,6 +220,7 @@ export class ExecutionLifecycleService {
this.activeListeners.clear();
this.exitedExecutionInfo.clear();
this.backgroundCompletionListeners.clear();
this.injectionService = null;
this.nextExecutionId = NON_PROCESS_EXECUTION_ID_START;
}
@@ -323,6 +334,16 @@ export class ExecutionLifecycleService {
error: result.error,
injectionText,
};
// Inject directly into the model conversation if injection text is
// available and the injection service has been wired up.
if (injectionText && this.injectionService) {
this.injectionService.addInjection(
injectionText,
'background_completion',
);
}
for (const listener of this.backgroundCompletionListeners) {
listener(info);
}