import { describe, expect, it, vi } from 'vitest';
import { Agent } from '../../../agent/agent.js';
import { BeforeToolCallEvent } from '../../../hooks/events.js';
import { HookRegistryImplementation } from '../../../hooks/registry.js';
import { MockMessageModel } from '../../../__fixtures__/mock-message-model.js';
import { LLMSteeringHandler } from '../handlers/llm.js';
function getHookRegistry(agent) {
    return agent._hooksRegistry;
}
function structuredOutputModel(decision) {
    return new MockMessageModel().addTurn({
        type: 'toolUseBlock',
        name: 'strands_structured_output',
        toolUseId: 'inner-1',
        input: decision,
    });
}
describe('LLMSteeringHandler', () => {
    const toolUse = { name: 'searchWeb', toolUseId: 'tu-1', input: { q: 'hi' } };
    it("defaults to the parent agent's model when none is configured", async () => {
        const model = structuredOutputModel({ type: 'proceed', reason: 'no concerning patterns' });
        const streamSpy = vi.spyOn(model, 'stream');
        const handler = new LLMSteeringHandler({
            systemPrompt: 'You are a steering agent.',
            contextProviders: [],
        });
        const agent = new Agent({ model, interventions: [handler] });
        await agent.initialize();
        const event = new BeforeToolCallEvent({ agent, toolUse, tool: undefined, invocationState: {} });
        await getHookRegistry(agent).invokeCallbacks(event);
        expect(streamSpy).toHaveBeenCalledTimes(1);
        expect(event.cancel).toBe(false);
    });
    it('uses the configured model in preference to the agent model', async () => {
        const agentModel = new MockMessageModel().addTurn({ type: 'textBlock', text: 'unused' });
        const configuredModel = structuredOutputModel({ type: 'proceed', reason: 'ok' });
        const agentStreamSpy = vi.spyOn(agentModel, 'stream');
        const configuredStreamSpy = vi.spyOn(configuredModel, 'stream');
        const handler = new LLMSteeringHandler({
            systemPrompt: 'You are a steering agent.',
            model: configuredModel,
            contextProviders: [],
        });
        const agent = new Agent({ model: agentModel, interventions: [handler] });
        await agent.initialize();
        const event = new BeforeToolCallEvent({ agent, toolUse, tool: undefined, invocationState: {} });
        await getHookRegistry(agent).invokeCallbacks(event);
        expect(configuredStreamSpy).toHaveBeenCalledTimes(1);
        expect(agentStreamSpy).not.toHaveBeenCalled();
    });
    it('throws when no model is configured and the handler has no parent agent', async () => {
        const handler = new LLMSteeringHandler({
            systemPrompt: 'You are a steering agent.',
            contextProviders: [],
        });
        // Detached: never attached to an agent, never observed.
        await expect(handler.beforeToolCall({ toolUse })).rejects.toThrow(/no model/i);
    });
});
//# sourceMappingURL=llm.test.js.map