fix(core): isolate subagent thread context (#26449)

This commit is contained in:
AK
2026-05-13 11:55:17 -07:00
committed by GitHub
parent 71a2c0264e
commit 9da30b8831
4 changed files with 18 additions and 18 deletions
+11 -12
View File
@@ -49,6 +49,7 @@ vi.mock('../tools/mcp-client-manager.js', () => ({
}));
import { debugLogger } from '../utils/debugLogger.js';
import { runWithToolCallContext } from '../utils/toolCallContext.js';
import { LocalAgentExecutor, type ActivityCallback } from './local-executor.js';
import { makeFakeConfig } from '../test-utils/config.js';
import { ToolRegistry } from '../tools/tool-registry.js';
@@ -708,21 +709,19 @@ describe('LocalAgentExecutor', () => {
expect(agentRegistry.getTool(MOCK_TOOL_NOT_ALLOWED.name)).toBeUndefined();
});
it('should use parentPromptId from context to create agentId', async () => {
const parentId = 'parent-id';
Object.defineProperty(mockConfig, 'promptId', {
get: () => parentId,
configurable: true,
});
it('should not include parentCallId in agentId even when available', async () => {
const definition = createTestDefinition();
const executor = await LocalAgentExecutor.create(
definition,
mockConfig,
onActivity,
const parentCallId = 'parent-call-123';
const executor = await runWithToolCallContext(
{ callId: parentCallId, schedulerId: 'test-scheduler' },
() => LocalAgentExecutor.create(definition, mockConfig, onActivity),
);
expect(executor['agentId']).toBeDefined();
expect(executor['agentId']).not.toContain(parentCallId);
expect(executor['agentId']).toMatch(
/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i,
);
});
it('should correctly apply templates to initialMessages', async () => {
+2 -1
View File
@@ -6,6 +6,7 @@
import { type AgentLoopContext } from '../config/agent-loop-context.js';
import { reportError } from '../utils/errorReporting.js';
import { randomUUID } from 'node:crypto';
import { ApprovalMode } from '../policy/types.js';
import { GeminiChat, StreamEventType } from '../core/geminiChat.js';
import {
@@ -315,7 +316,7 @@ export class LocalAgentExecutor<TOutput extends z.ZodTypeAny> {
this.parentCallId = parentCallId;
this.cache = new LRUCache<string, string>(10);
this.agentId = Math.random().toString(36).slice(2, 8);
this.agentId = randomUUID();
}
/**
+2 -2
View File
@@ -55,7 +55,7 @@ describe('GeminiCliAgent Skills Integration', () => {
// Expect pirate speak
expect(responseText.toLowerCase()).toContain('arrr');
}, 60000);
}, 120000);
it('loads and activates a skill from a root', async () => {
const goldenFile = getGoldenPath('skill-root-success');
@@ -88,5 +88,5 @@ describe('GeminiCliAgent Skills Integration', () => {
// Expect confirmation or pirate speak
expect(responseText.toLowerCase()).toContain('arrr');
}, 60000);
}, 120000);
});
+3 -3
View File
@@ -57,7 +57,7 @@ describe('GeminiCliAgent Tool Integration', () => {
.join('');
expect(responseText).toContain('8');
});
}, 20000);
it('handles ModelVisibleError correctly', async () => {
const goldenFile = getGoldenPath('tool-error-recovery');
@@ -103,7 +103,7 @@ describe('GeminiCliAgent Tool Integration', () => {
// The model should see the error "Tool failed visibly" and report it back.
expect(responseText).toContain('Tool failed visibly');
});
}, 20000);
it('handles sendErrorsToModel: true correctly', async () => {
const goldenFile = getGoldenPath('tool-catchall-error');
@@ -145,5 +145,5 @@ describe('GeminiCliAgent Tool Integration', () => {
// The model should report the caught standard error.
expect(responseText.toLowerCase()).toContain('error');
});
}, 20000);
});