Ctrl K
ComunidadGuías…

test/tools/test_resolve.py

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
# Copyright (c) 2026, AG2ai, Inc., AG2ai open-source projects maintainers and core contributors
#
# SPDX-License-Identifier: Apache-2.0

from collections.abc import Callable

import pytest

from ag2 import Context, Variable
from ag2.tools import ImageGenerationTool, UserLocation, WebSearchTool
from ag2.tools.builtin._resolve import resolve_variable
from ag2.tools.builtin.file_search import FileSearchTool, FileSearchToolSchema
from ag2.tools.builtin.google_maps import GoogleMapsTool, GoogleMapsToolSchema
from ag2.tools.builtin.image_generation import ImageGenerationToolSchema
from ag2.tools.builtin.mcp_server import MCPServerTool, MCPServerToolSchema
from ag2.tools.builtin.retrieval import RetrievalTool, RetrievalToolSchema
from ag2.tools.builtin.shell import ContainerAutoEnvironment, ShellTool, ShellToolSchema
from ag2.tools.builtin.web_fetch import UrlSources, WebFetchTool, WebFetchToolSchema
from ag2.tools.builtin.web_search import WebSearchToolSchema
from ag2.tools.builtin.x_search import XSearchTool, XSearchToolSchema


class TestResolveVariable:
    def test_passthrough(self, context: Context) -> None:
        assert resolve_variable("hello", context) == "hello"
        assert resolve_variable(42, context) == 42
        assert resolve_variable(None, context) is None

    def test_from_context(self, make_context: Callable[..., Context]) -> None:
        loc = UserLocation(country="US")
        ctx = make_context(user_location=loc)

        result = resolve_variable(Variable("user_location"), ctx)

        assert result is loc

    def test_default(self, context: Context) -> None:
        fallback = UserLocation(country="DE")

        result = resolve_variable(Variable("user_location", default=fallback), context)

        assert result is fallback

    def test_default_factory(self, context: Context) -> None:
        result = resolve_variable(Variable("counter", default_factory=dict), context)

        assert result == {}

    def test_context_takes_precedence_over_default(self, make_context: Callable[..., Context]) -> None:
        ctx = make_context(mode="fast")
        result = resolve_variable(Variable("mode", default="slow"), ctx)

        assert result == "fast"

    def test_missing_raises(self, context: Context) -> None:
        with pytest.raises(KeyError, match="user_location"):
            resolve_variable(Variable("user_location"), context)


class TestWebSearchToolVariable:
    @pytest.mark.asyncio
    async def test_resolved(self, make_context: Callable[..., Context]) -> None:
        loc = UserLocation(city="Berlin", country="DE")
        ctx = make_context(loc=loc)
        tool = WebSearchTool(user_location=Variable("loc"))

        [schema] = await tool.schemas(ctx)

        assert isinstance(schema, WebSearchToolSchema)
        assert schema.user_location is loc

    @pytest.mark.asyncio
    async def test_missing_raises(self, context: Context) -> None:
        tool = WebSearchTool(user_location=Variable("loc"))

        with pytest.raises(KeyError, match="loc"):
            await tool.schemas(context)


class TestWebFetchToolVariable:
    @pytest.mark.asyncio
    async def test_resolved(self, make_context: Callable[..., Context]) -> None:
        ctx = make_context(limit=10)
        tool = WebFetchTool(max_uses=Variable("limit"))

        [schema] = await tool.schemas(ctx)

        assert isinstance(schema, WebFetchToolSchema)
        assert schema.max_uses == 10

    @pytest.mark.asyncio
    async def test_missing_raises(self, context: Context) -> None:
        tool = WebFetchTool(max_uses=Variable("limit"))

        with pytest.raises(KeyError, match="limit"):
            await tool.schemas(context)


class TestShellToolVariable:
    @pytest.mark.asyncio
    async def test_resolved(self, make_context: Callable[..., Context]) -> None:
        env = ContainerAutoEnvironment()
        ctx = make_context(env=env)
        tool = ShellTool(environment=Variable("env"))

        [schema] = await tool.schemas(ctx)

        assert isinstance(schema, ShellToolSchema)
        assert schema.environment is env

    @pytest.mark.asyncio
    async def test_missing_raises(self, context: Context) -> None:
        tool = ShellTool(environment=Variable("env"))

        with pytest.raises(KeyError, match="env"):
            await tool.schemas(context)


class TestImageGenerationToolVariable:
    @pytest.mark.asyncio
    async def test_resolved(self, make_context: Callable[..., Context]) -> None:
        ctx = make_context(image_size="1536x1024")
        tool = ImageGenerationTool(quality="high", size=Variable("image_size"))

        [schema] = await tool.schemas(ctx)

        assert isinstance(schema, ImageGenerationToolSchema)
        assert schema.quality == "high"
        assert schema.size == "1536x1024"

    @pytest.mark.asyncio
    async def test_missing_raises(self, context: Context) -> None:
        tool = ImageGenerationTool(partial_images=Variable("partial_images"))

        with pytest.raises(KeyError, match="partial_images"):
            await tool.schemas(context)


class TestMCPServerToolVariable:
    @pytest.mark.asyncio
    async def test_resolved(self, make_context: Callable[..., Context]) -> None:
        ctx = make_context(url="https://mcp.example.com/sse")
        tool = MCPServerTool(server_url=Variable("url"), server_label="test-mcp")

        [schema] = await tool.schemas(ctx)

        assert isinstance(schema, MCPServerToolSchema)
        assert schema.server_url == "https://mcp.example.com/sse"

    @pytest.mark.asyncio
    async def test_missing_raises(self, context: Context) -> None:
        tool = MCPServerTool(server_url=Variable("url"), server_label="test-mcp")

        with pytest.raises(KeyError, match="url"):
            await tool.schemas(context)


class TestXSearchToolVariable:
    @pytest.mark.asyncio
    async def test_resolved(self, make_context: Callable[..., Context]) -> None:
        ctx = make_context(handles=["xai"])
        tool = XSearchTool(allowed_x_handles=Variable("handles"))

        [schema] = await tool.schemas(ctx)

        assert isinstance(schema, XSearchToolSchema)
        assert schema.allowed_x_handles == ["xai"]

    @pytest.mark.asyncio
    async def test_missing_raises(self, context: Context) -> None:
        tool = XSearchTool(allowed_x_handles=Variable("handles"))

        with pytest.raises(KeyError, match="handles"):
            await tool.schemas(context)


class TestRetrievalToolVariable:
    @pytest.mark.asyncio
    async def test_resolved(self, make_context: Callable[..., Context]) -> None:
        ctx = make_context(kid="kb_from_ctx")
        tool = RetrievalTool(Variable("kid"))

        [schema] = await tool.schemas(ctx)

        assert isinstance(schema, RetrievalToolSchema)
        assert schema.knowledge_id == "kb_from_ctx"

    @pytest.mark.asyncio
    async def test_missing_raises(self, context: Context) -> None:
        tool = RetrievalTool(Variable("kid"))

        with pytest.raises(KeyError, match="kid"):
            await tool.schemas(context)


@pytest.mark.asyncio
class TestFileSearchToolVariable:
    async def test_store_names_resolved(self, make_context: Callable[..., Context]) -> None:
        ctx = make_context(stores=["projects/p/fileSearchStores/s"])

        tool = FileSearchTool(store_names=Variable("stores"), metadata_filter='author="A"')
        [schema] = await tool.schemas(ctx)

        assert isinstance(schema, FileSearchToolSchema)
        assert schema.store_names == ["projects/p/fileSearchStores/s"]
        assert schema.metadata_filter == 'author="A"'

    async def test_store_names_missing_raises(self, context: Context) -> None:
        tool = FileSearchTool(store_names=Variable("stores"))

        with pytest.raises(KeyError, match="stores"):
            await tool.schemas(context)

    async def test_vector_store_ids_resolved(self, make_context: Callable[..., Context]) -> None:
        ctx = make_context(stores=["vs_1"])

        tool = FileSearchTool(vector_store_ids=Variable("stores"))
        [schema] = await tool.schemas(ctx)

        assert isinstance(schema, FileSearchToolSchema)
        assert schema.vector_store_ids == ["vs_1"]

    async def test_vector_store_ids_missing_raises(self, context: Context) -> None:
        tool = FileSearchTool(vector_store_ids=Variable("stores"))

        with pytest.raises(KeyError, match="stores"):
            await tool.schemas(context)


@pytest.mark.asyncio
class TestGoogleMapsToolVariable:
    async def test_resolved(self, make_context: Callable[..., Context]) -> None:
        ctx = make_context(lat=37.4)

        tool = GoogleMapsTool(latitude=Variable("lat"), longitude=-122.1)
        [schema] = await tool.schemas(ctx)

        assert isinstance(schema, GoogleMapsToolSchema)
        assert schema.latitude == 37.4
        assert schema.longitude == -122.1

    async def test_missing_raises(self, context: Context) -> None:
        tool = GoogleMapsTool(latitude=Variable("lat"))

        with pytest.raises(KeyError):
            await tool.schemas(context)


@pytest.mark.asyncio
class TestWebFetchUrlSourcesVariable:
    async def test_resolved(self, make_context: Callable[..., Context]) -> None:
        sources = UrlSources(user_input="none")
        ctx = make_context(fetch_policy=sources)
        tool = WebFetchTool(url_sources=Variable("fetch_policy"))

        [schema] = await tool.schemas(ctx)

        assert isinstance(schema, WebFetchToolSchema)
        assert schema.url_sources is sources

    async def test_missing_raises(self, context: Context) -> None:
        tool = WebFetchTool(url_sources=Variable("fetch_policy"))

        with pytest.raises(KeyError, match="fetch_policy"):
            await tool.schemas(context)