first commit
Security: Sync from Public / sync-from-public (push) Has been cancelled
Test: Benchmark Nightly / build (push) Has been cancelled
Test: Benchmark Nightly / Notify Cats on failure (push) Has been cancelled
CI: Python / Checks (push) Has been cancelled
Test: Evals Python / Workflow Comparison Python (push) Has been cancelled
Util: Check Docs URLs / check-docs-urls (push) Has been cancelled
Test: Visual Storybook / Cloudflare Pages (push) Has been cancelled
Test: E2E Performance / build-and-test-performance (push) Has been cancelled
Test: Workflows Nightly / Run Workflow Tests (push) Has been cancelled
Util: Cleanup CI Docker Images / Delete stale CI images (push) Has been cancelled
Test: Benchmark Destroy Env / build (push) Has been cancelled
Util: Update Node Popularity / update-popularity (push) Has been cancelled
Test: E2E Coverage Weekly / Coverage Tests (push) Has been cancelled

This commit is contained in:
2026-03-17 16:22:57 +03:30
commit 3d5eaf9445
15349 changed files with 2847338 additions and 0 deletions
@@ -0,0 +1,13 @@
import type { Tool } from '@langchain/core/tools';
import type { ExecutionContext, ExecutionStrategy } from './ExecutionStrategy';
export class DirectExecutionStrategy implements ExecutionStrategy {
async executeTool(
tool: Tool,
args: Record<string, unknown>,
_context: ExecutionContext,
): Promise<unknown> {
return await tool.invoke(args);
}
}
@@ -0,0 +1,33 @@
import type { Tool } from '@langchain/core/tools';
import { DirectExecutionStrategy } from './DirectExecutionStrategy';
import type { ExecutionContext, ExecutionStrategy } from './ExecutionStrategy';
import { QueuedExecutionStrategy } from './QueuedExecutionStrategy';
export class ExecutionCoordinator {
private strategy: ExecutionStrategy;
constructor(strategy?: ExecutionStrategy) {
this.strategy = strategy ?? new DirectExecutionStrategy();
}
async executeTool(
tool: Tool,
args: Record<string, unknown>,
context: ExecutionContext,
): Promise<unknown> {
return await this.strategy.executeTool(tool, args, context);
}
setStrategy(strategy: ExecutionStrategy): void {
this.strategy = strategy;
}
getStrategy(): ExecutionStrategy {
return this.strategy;
}
isQueueMode(): boolean {
return this.strategy instanceof QueuedExecutionStrategy;
}
}
@@ -0,0 +1,14 @@
import type { Tool } from '@langchain/core/tools';
export interface ExecutionContext {
sessionId: string;
messageId?: string;
}
export interface ExecutionStrategy {
executeTool(
tool: Tool,
args: Record<string, unknown>,
context: ExecutionContext,
): Promise<unknown>;
}
@@ -0,0 +1,81 @@
export interface PendingCall {
toolName: string;
arguments: Record<string, unknown>;
resolve: (result: unknown) => void;
reject: (error: Error) => void;
timer: ReturnType<typeof setTimeout>;
}
export class PendingCallsManager {
private pendingCalls: Record<string, PendingCall> = {};
async waitForResult(
callId: string,
toolName: string,
args: Record<string, unknown>,
timeoutMs: number,
): Promise<unknown> {
return await new Promise((resolve, reject) => {
const timer = setTimeout(() => {
if (this.pendingCalls[callId]) {
this.reject(callId, new Error('Worker tool execution timeout'));
}
}, timeoutMs);
this.pendingCalls[callId] = {
toolName,
arguments: args,
resolve,
reject,
timer,
};
});
}
resolve(callId: string, result: unknown): boolean {
const pending = this.pendingCalls[callId];
if (pending) {
clearTimeout(pending.timer);
pending.resolve(result);
delete this.pendingCalls[callId];
return true;
}
return false;
}
reject(callId: string, error: Error): boolean {
const pending = this.pendingCalls[callId];
if (pending) {
clearTimeout(pending.timer);
pending.reject(error);
delete this.pendingCalls[callId];
return true;
}
return false;
}
get(callId: string): PendingCall | undefined {
return this.pendingCalls[callId];
}
has(callId: string): boolean {
return callId in this.pendingCalls;
}
remove(callId: string): void {
delete this.pendingCalls[callId];
}
cleanupBySessionId(sessionId: string): void {
for (const callId of Object.keys(this.pendingCalls)) {
if (callId.startsWith(`${sessionId}_`)) {
const pending = this.pendingCalls[callId];
if (pending) {
clearTimeout(pending.timer);
pending.resolve(undefined);
}
delete this.pendingCalls[callId];
}
}
}
}
@@ -0,0 +1,35 @@
import type { Tool } from '@langchain/core/tools';
import type { ExecutionContext, ExecutionStrategy } from './ExecutionStrategy';
import type { PendingCallsManager } from './PendingCallsManager';
const DEFAULT_TIMEOUT_MS = 120000;
export class QueuedExecutionStrategy implements ExecutionStrategy {
constructor(
private pendingCalls: PendingCallsManager,
private timeoutMs: number = DEFAULT_TIMEOUT_MS,
) {}
async executeTool(
tool: Tool,
args: Record<string, unknown>,
context: ExecutionContext,
): Promise<unknown> {
const callId = `${context.sessionId}_${context.messageId ?? 'default'}`;
return await this.pendingCalls.waitForResult(callId, tool.name, args, this.timeoutMs);
}
resolveToolCall(callId: string, result: unknown): boolean {
return this.pendingCalls.resolve(callId, result);
}
rejectToolCall(callId: string, error: Error): boolean {
return this.pendingCalls.reject(callId, error);
}
getPendingCallsManager(): PendingCallsManager {
return this.pendingCalls;
}
}
@@ -0,0 +1,93 @@
import { createMockTool } from '../../__tests__/helpers';
import { DirectExecutionStrategy } from '../DirectExecutionStrategy';
describe('DirectExecutionStrategy', () => {
let strategy: DirectExecutionStrategy;
beforeEach(() => {
strategy = new DirectExecutionStrategy();
});
describe('executeTool', () => {
it('should invoke tool with provided arguments', async () => {
const tool = createMockTool('test-tool', { invokeReturn: { result: 'success' } });
const result = await strategy.executeTool(
tool,
{ input: 'test' },
{ sessionId: 'session-1' },
);
expect(tool.invoke).toHaveBeenCalledWith({ input: 'test' });
expect(result).toEqual({ result: 'success' });
});
it('should propagate tool errors', async () => {
const tool = createMockTool('failing-tool', {
invokeError: new Error('Tool failed'),
});
await expect(strategy.executeTool(tool, {}, { sessionId: 'session-1' })).rejects.toThrow(
'Tool failed',
);
});
it('should pass empty arguments correctly', async () => {
const tool = createMockTool('no-args-tool', { invokeReturn: 'result' });
await strategy.executeTool(tool, {}, { sessionId: 'session-1' });
expect(tool.invoke).toHaveBeenCalledWith({});
});
it('should handle complex arguments', async () => {
const tool = createMockTool('complex-tool', { invokeReturn: 'result' });
const complexArgs = {
nested: { deep: { value: 123 } },
array: [1, 2, 3],
text: 'hello',
};
await strategy.executeTool(tool, complexArgs, { sessionId: 'session-1' });
expect(tool.invoke).toHaveBeenCalledWith(complexArgs);
});
it('should handle various return types', async () => {
const stringTool = createMockTool('string-tool', { invokeReturn: 'string result' });
const numberTool = createMockTool('number-tool', { invokeReturn: 42 });
const arrayTool = createMockTool('array-tool', { invokeReturn: [1, 2, 3] });
const nullTool = createMockTool('null-tool', { invokeReturn: null });
const context = { sessionId: 'session-1' };
expect(await strategy.executeTool(stringTool, {}, context)).toBe('string result');
expect(await strategy.executeTool(numberTool, {}, context)).toBe(42);
expect(await strategy.executeTool(arrayTool, {}, context)).toEqual([1, 2, 3]);
expect(await strategy.executeTool(nullTool, {}, context)).toBeNull();
});
it('should handle execution context with messageId', async () => {
const tool = createMockTool('test-tool', { invokeReturn: 'result' });
const result = await strategy.executeTool(
tool,
{ arg: 'value' },
{ sessionId: 'session-1', messageId: 'msg-123' },
);
expect(result).toBe('result');
expect(tool.invoke).toHaveBeenCalledWith({ arg: 'value' });
});
it('should propagate TypeError from tool', async () => {
const tool = createMockTool('type-error-tool', {
invokeError: new TypeError('Invalid type'),
});
await expect(strategy.executeTool(tool, {}, { sessionId: 'session-1' })).rejects.toThrow(
TypeError,
);
});
});
});
@@ -0,0 +1,134 @@
import { createMockTool } from '../../__tests__/helpers';
import { DirectExecutionStrategy } from '../DirectExecutionStrategy';
import { ExecutionCoordinator } from '../ExecutionCoordinator';
import { PendingCallsManager } from '../PendingCallsManager';
import { QueuedExecutionStrategy } from '../QueuedExecutionStrategy';
describe('ExecutionCoordinator', () => {
describe('default behavior', () => {
it('should use DirectExecutionStrategy by default', () => {
const coordinator = new ExecutionCoordinator();
expect(coordinator.getStrategy()).toBeInstanceOf(DirectExecutionStrategy);
});
it('should not be in queue mode by default', () => {
const coordinator = new ExecutionCoordinator();
expect(coordinator.isQueueMode()).toBe(false);
});
});
describe('constructor with custom strategy', () => {
it('should accept custom strategy in constructor', () => {
const customStrategy = new DirectExecutionStrategy();
const coordinator = new ExecutionCoordinator(customStrategy);
expect(coordinator.getStrategy()).toBe(customStrategy);
});
it('should accept QueuedExecutionStrategy in constructor', () => {
const queuedStrategy = new QueuedExecutionStrategy(new PendingCallsManager());
const coordinator = new ExecutionCoordinator(queuedStrategy);
expect(coordinator.getStrategy()).toBe(queuedStrategy);
expect(coordinator.isQueueMode()).toBe(true);
});
});
describe('strategy management', () => {
it('should allow setting custom strategy', () => {
const coordinator = new ExecutionCoordinator();
const queuedStrategy = new QueuedExecutionStrategy(new PendingCallsManager());
coordinator.setStrategy(queuedStrategy);
expect(coordinator.getStrategy()).toBe(queuedStrategy);
});
it('should report queue mode when using QueuedExecutionStrategy', () => {
const coordinator = new ExecutionCoordinator();
coordinator.setStrategy(new QueuedExecutionStrategy(new PendingCallsManager()));
expect(coordinator.isQueueMode()).toBe(true);
});
it('should report non-queue mode when switching back to DirectExecutionStrategy', () => {
const coordinator = new ExecutionCoordinator();
coordinator.setStrategy(new QueuedExecutionStrategy(new PendingCallsManager()));
coordinator.setStrategy(new DirectExecutionStrategy());
expect(coordinator.isQueueMode()).toBe(false);
});
});
describe('executeTool', () => {
it('should delegate to current strategy', async () => {
const coordinator = new ExecutionCoordinator();
const tool = createMockTool('test', { invokeReturn: 'result' });
const result = await coordinator.executeTool(tool, { input: 'test' }, { sessionId: 's1' });
expect(tool.invoke).toHaveBeenCalledWith({ input: 'test' });
expect(result).toBe('result');
});
it('should use DirectExecutionStrategy by default', async () => {
const coordinator = new ExecutionCoordinator();
const tool = createMockTool('test', { invokeReturn: { data: 'from-tool' } });
const result = await coordinator.executeTool(tool, {}, { sessionId: 'session-1' });
expect(result).toEqual({ data: 'from-tool' });
expect(tool.invoke).toHaveBeenCalled();
});
it('should propagate errors from strategy', async () => {
const coordinator = new ExecutionCoordinator();
const tool = createMockTool('failing-tool', {
invokeError: new Error('Strategy error'),
});
await expect(coordinator.executeTool(tool, {}, { sessionId: 'session-1' })).rejects.toThrow(
'Strategy error',
);
});
it('should pass context to strategy', async () => {
const mockStrategy = {
executeTool: jest.fn().mockResolvedValue('result'),
};
const coordinator = new ExecutionCoordinator(mockStrategy);
const tool = createMockTool('test', { invokeReturn: 'result' });
const context = { sessionId: 'session-1', messageId: 'msg-123' };
await coordinator.executeTool(tool, { arg: 'value' }, context);
expect(mockStrategy.executeTool).toHaveBeenCalledWith(tool, { arg: 'value' }, context);
});
});
describe('isQueueMode detection', () => {
it('should detect QueuedExecutionStrategy by constructor name', () => {
const coordinator = new ExecutionCoordinator();
const queuedStrategy = new QueuedExecutionStrategy(new PendingCallsManager());
coordinator.setStrategy(queuedStrategy);
expect(coordinator.isQueueMode()).toBe(true);
});
it('should return false for DirectExecutionStrategy', () => {
const coordinator = new ExecutionCoordinator(new DirectExecutionStrategy());
expect(coordinator.isQueueMode()).toBe(false);
});
it('should return false for anonymous strategy implementations', () => {
const coordinator = new ExecutionCoordinator();
const anonymousStrategy = {
executeTool: jest.fn().mockResolvedValue('result'),
};
coordinator.setStrategy(anonymousStrategy);
expect(coordinator.isQueueMode()).toBe(false);
});
});
});
@@ -0,0 +1,251 @@
import { PendingCallsManager } from '../PendingCallsManager';
describe('PendingCallsManager', () => {
let manager: PendingCallsManager;
beforeEach(() => {
manager = new PendingCallsManager();
jest.useFakeTimers();
});
afterEach(() => {
jest.useRealTimers();
});
describe('waitForResult', () => {
it('should resolve when result is provided via resolve()', async () => {
const resultPromise = manager.waitForResult('call-1', 'test-tool', {}, 5000);
manager.resolve('call-1', { success: true });
await expect(resultPromise).resolves.toEqual({ success: true });
});
it('should reject on timeout with meaningful error', async () => {
const resultPromise = manager.waitForResult('call-1', 'test-tool', {}, 1000);
jest.advanceTimersByTime(1001);
await expect(resultPromise).rejects.toThrow('Worker tool execution timeout');
});
it('should track pending call while waiting', async () => {
const promise = manager.waitForResult('call-1', 'test-tool', {}, 5000);
expect(manager.has('call-1')).toBe(true);
// Clean up to avoid unhandled rejection
manager.resolve('call-1', undefined);
await promise;
});
it('should remove call from pending after resolution', async () => {
const resultPromise = manager.waitForResult('call-1', 'test-tool', {}, 5000);
manager.resolve('call-1', 'result');
await resultPromise;
expect(manager.has('call-1')).toBe(false);
});
it('should remove call from pending after timeout', async () => {
const resultPromise = manager.waitForResult('call-1', 'test-tool', {}, 1000);
jest.advanceTimersByTime(1001);
await expect(resultPromise).rejects.toThrow();
expect(manager.has('call-1')).toBe(false);
});
it('should store tool name and arguments', async () => {
const args = { city: 'London' };
const promise = manager.waitForResult('call-1', 'get_weather', args, 5000);
const pendingCall = manager.get('call-1');
expect(pendingCall).toBeDefined();
expect(pendingCall?.toolName).toBe('get_weather');
expect(pendingCall?.arguments).toEqual(args);
// Clean up
manager.resolve('call-1', undefined);
await promise;
});
it('should handle multiple concurrent calls', async () => {
const promise1 = manager.waitForResult('call-1', 'tool-1', {}, 5000);
const promise2 = manager.waitForResult('call-2', 'tool-2', {}, 5000);
const promise3 = manager.waitForResult('call-3', 'tool-3', {}, 5000);
expect(manager.has('call-1')).toBe(true);
expect(manager.has('call-2')).toBe(true);
expect(manager.has('call-3')).toBe(true);
manager.resolve('call-1', 'result-1');
manager.resolve('call-2', 'result-2');
manager.resolve('call-3', 'result-3');
await expect(promise1).resolves.toBe('result-1');
await expect(promise2).resolves.toBe('result-2');
await expect(promise3).resolves.toBe('result-3');
});
});
describe('resolve', () => {
it('should return true when call exists', async () => {
const promise = manager.waitForResult('call-1', 'test-tool', {}, 5000);
expect(manager.resolve('call-1', 'result')).toBe(true);
await promise;
});
it('should return false when call does not exist', () => {
expect(manager.resolve('non-existent', 'result')).toBe(false);
});
it('should handle resolving with various result types', async () => {
const promise1 = manager.waitForResult('call-1', 'tool', {}, 5000);
const promise2 = manager.waitForResult('call-2', 'tool', {}, 5000);
const promise3 = manager.waitForResult('call-3', 'tool', {}, 5000);
const promise4 = manager.waitForResult('call-4', 'tool', {}, 5000);
manager.resolve('call-1', undefined);
manager.resolve('call-2', null);
manager.resolve('call-3', { complex: { nested: 'data' } });
manager.resolve('call-4', [1, 2, 3]);
await expect(promise1).resolves.toBeUndefined();
await expect(promise2).resolves.toBeNull();
await expect(promise3).resolves.toEqual({ complex: { nested: 'data' } });
await expect(promise4).resolves.toEqual([1, 2, 3]);
});
it('should only resolve once (subsequent resolves return false)', async () => {
const promise = manager.waitForResult('call-1', 'test-tool', {}, 5000);
expect(manager.resolve('call-1', 'first')).toBe(true);
expect(manager.resolve('call-1', 'second')).toBe(false);
await promise;
});
});
describe('reject', () => {
it('should reject pending call with error', async () => {
const resultPromise = manager.waitForResult('call-1', 'test-tool', {}, 5000);
const error = new Error('Tool execution failed');
manager.reject('call-1', error);
await expect(resultPromise).rejects.toThrow('Tool execution failed');
});
it('should return true when call exists', async () => {
const promise = manager.waitForResult('call-1', 'test-tool', {}, 5000);
expect(manager.reject('call-1', new Error('test'))).toBe(true);
// Must await/catch the rejection to avoid unhandled rejection
await expect(promise).rejects.toThrow('test');
});
it('should return false when call does not exist', () => {
expect(manager.reject('non-existent', new Error('test'))).toBe(false);
});
it('should remove call from pending after rejection', async () => {
const resultPromise = manager.waitForResult('call-1', 'test-tool', {}, 5000);
manager.reject('call-1', new Error('test'));
await expect(resultPromise).rejects.toThrow();
expect(manager.has('call-1')).toBe(false);
});
});
describe('cleanupBySessionId', () => {
it('should resolve all calls matching session prefix with underscore', async () => {
const promise1 = manager.waitForResult('session-1_msg-1', 'tool', {}, 5000);
const promise2 = manager.waitForResult('session-1_msg-2', 'tool', {}, 5000);
const promise3 = manager.waitForResult('session-2_msg-1', 'tool', {}, 5000);
manager.cleanupBySessionId('session-1');
await expect(promise1).resolves.toBeUndefined();
await expect(promise2).resolves.toBeUndefined();
expect(manager.has('session-1_msg-1')).toBe(false);
expect(manager.has('session-1_msg-2')).toBe(false);
expect(manager.has('session-2_msg-1')).toBe(true);
manager.resolve('session-2_msg-1', 'result');
await promise3;
});
it('should not cleanup calls without underscore separator', async () => {
const promise = manager.waitForResult('session-1', 'tool', {}, 5000);
manager.cleanupBySessionId('session-1');
expect(manager.has('session-1')).toBe(true);
manager.resolve('session-1', 'result');
await promise;
});
it('should handle cleanup when no matching sessions', async () => {
const promise = manager.waitForResult('other-session_msg-1', 'tool', {}, 5000);
expect(() => manager.cleanupBySessionId('session-1')).not.toThrow();
expect(manager.has('other-session_msg-1')).toBe(true);
manager.resolve('other-session_msg-1', 'result');
await promise;
});
it('should handle cleanup when no pending calls', () => {
expect(() => manager.cleanupBySessionId('session-1')).not.toThrow();
});
});
describe('get and has', () => {
it('should return call info for existing call', async () => {
const promise = manager.waitForResult('call-1', 'test-tool', { arg: 'value' }, 5000);
const info = manager.get('call-1');
expect(info).toBeDefined();
expect(info).toHaveProperty('resolve');
expect(info).toHaveProperty('reject');
expect(info).toHaveProperty('toolName', 'test-tool');
expect(info).toHaveProperty('arguments', { arg: 'value' });
manager.resolve('call-1', 'result');
await promise;
});
it('should return undefined for non-existent call', () => {
expect(manager.get('non-existent')).toBeUndefined();
});
it('should return true for existing call', async () => {
const promise = manager.waitForResult('call-1', 'tool', {}, 5000);
expect(manager.has('call-1')).toBe(true);
manager.resolve('call-1', 'result');
await promise;
});
it('should return false for non-existent call', () => {
expect(manager.has('non-existent')).toBe(false);
});
});
describe('remove', () => {
it('should remove pending call without resolving or rejecting', async () => {
const promise = manager.waitForResult('call-1', 'tool', {}, 5000);
manager.remove('call-1');
expect(manager.has('call-1')).toBe(false);
// Note: The promise will never resolve/reject when removed this way
// This is expected behavior - remove() is for cleanup when we don't care about the result
// We need to avoid the unhandled rejection by advancing time to trigger timeout
// but the promise was removed so it won't reject. We handle this by catching any potential rejection
await Promise.race([promise.catch(() => {}), Promise.resolve()]);
});
it('should handle removing non-existent call', () => {
expect(() => manager.remove('non-existent')).not.toThrow();
});
});
});
@@ -0,0 +1,166 @@
import { createMockTool } from '../../__tests__/helpers';
import type { PendingCallsManager } from '../PendingCallsManager';
import { QueuedExecutionStrategy } from '../QueuedExecutionStrategy';
describe('QueuedExecutionStrategy', () => {
let strategy: QueuedExecutionStrategy;
let mockPendingCalls: jest.Mocked<PendingCallsManager>;
beforeEach(() => {
mockPendingCalls = {
waitForResult: jest.fn(),
resolve: jest.fn(),
reject: jest.fn(),
get: jest.fn(),
has: jest.fn(),
remove: jest.fn(),
cleanupBySessionId: jest.fn(),
} as unknown as jest.Mocked<PendingCallsManager>;
strategy = new QueuedExecutionStrategy(mockPendingCalls);
});
describe('executeTool', () => {
it('should create callId from sessionId and messageId', async () => {
mockPendingCalls.waitForResult.mockResolvedValue('result');
const tool = createMockTool('test-tool');
await strategy.executeTool(
tool,
{ arg: 'value' },
{ sessionId: 'session-1', messageId: 'msg-1' },
);
expect(mockPendingCalls.waitForResult).toHaveBeenCalledWith(
'session-1_msg-1',
'test-tool',
{ arg: 'value' },
expect.any(Number),
);
});
it('should create callId from sessionId with default suffix when no messageId', async () => {
mockPendingCalls.waitForResult.mockResolvedValue('result');
const tool = createMockTool('test-tool');
await strategy.executeTool(tool, {}, { sessionId: 'session-1' });
expect(mockPendingCalls.waitForResult).toHaveBeenCalledWith(
'session-1_default',
'test-tool',
{},
expect.any(Number),
);
});
it('should return result from pending calls manager', async () => {
mockPendingCalls.waitForResult.mockResolvedValue({ data: 'from-worker' });
const tool = createMockTool('test-tool');
const result = await strategy.executeTool(tool, {}, { sessionId: 'session-1' });
expect(result).toEqual({ data: 'from-worker' });
});
it('should pass tool name and arguments to waitForResult', async () => {
mockPendingCalls.waitForResult.mockResolvedValue('result');
const tool = createMockTool('get_weather');
const args = { city: 'London', units: 'metric' };
await strategy.executeTool(tool, args, { sessionId: 'session-1' });
expect(mockPendingCalls.waitForResult).toHaveBeenCalledWith(
expect.any(String),
'get_weather',
args,
expect.any(Number),
);
});
it('should use default timeout', async () => {
mockPendingCalls.waitForResult.mockResolvedValue('result');
const tool = createMockTool('test-tool');
await strategy.executeTool(tool, {}, { sessionId: 'session-1' });
expect(mockPendingCalls.waitForResult).toHaveBeenCalledWith(
expect.any(String),
expect.any(String),
expect.any(Object),
120000, // DEFAULT_TIMEOUT_MS
);
});
it('should propagate errors from pending calls manager', async () => {
mockPendingCalls.waitForResult.mockRejectedValue(new Error('Timeout'));
const tool = createMockTool('test-tool');
await expect(strategy.executeTool(tool, {}, { sessionId: 'session-1' })).rejects.toThrow(
'Timeout',
);
});
});
describe('with custom timeout', () => {
it('should use custom timeout when provided', async () => {
const customTimeout = 60000;
const customStrategy = new QueuedExecutionStrategy(mockPendingCalls, customTimeout);
mockPendingCalls.waitForResult.mockResolvedValue('result');
const tool = createMockTool('test-tool');
await customStrategy.executeTool(tool, {}, { sessionId: 'session-1' });
expect(mockPendingCalls.waitForResult).toHaveBeenCalledWith(
expect.any(String),
expect.any(String),
expect.any(Object),
customTimeout,
);
});
});
describe('resolveToolCall', () => {
it('should delegate to pendingCalls.resolve', () => {
mockPendingCalls.resolve.mockReturnValue(true);
const result = strategy.resolveToolCall('call-1', { success: true });
expect(mockPendingCalls.resolve).toHaveBeenCalledWith('call-1', { success: true });
expect(result).toBe(true);
});
it('should return false when call does not exist', () => {
mockPendingCalls.resolve.mockReturnValue(false);
const result = strategy.resolveToolCall('non-existent', 'result');
expect(result).toBe(false);
});
});
describe('rejectToolCall', () => {
it('should delegate to pendingCalls.reject', () => {
mockPendingCalls.reject.mockReturnValue(true);
const error = new Error('test');
const result = strategy.rejectToolCall('call-1', error);
expect(mockPendingCalls.reject).toHaveBeenCalledWith('call-1', error);
expect(result).toBe(true);
});
it('should return false when call does not exist', () => {
mockPendingCalls.reject.mockReturnValue(false);
const result = strategy.rejectToolCall('non-existent', new Error('test'));
expect(result).toBe(false);
});
});
describe('getPendingCallsManager', () => {
it('should return the pending calls manager', () => {
expect(strategy.getPendingCallsManager()).toBe(mockPendingCalls);
});
});
});
@@ -0,0 +1,5 @@
export type { ExecutionContext, ExecutionStrategy } from './ExecutionStrategy';
export * from './DirectExecutionStrategy';
export * from './QueuedExecutionStrategy';
export * from './PendingCallsManager';
export * from './ExecutionCoordinator';