Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.vectorshift.ai/llms.txt

Use this file to discover all available pages before exploring further.

Verifies that every way of creating a tool accepts approval_config and that the value flows through to the serialized save payload the backend consumes. Paths exercised:
1. Direct class instantiation            - ExaAiTool(...)
2. AgentTools namespace                  - AgentTools.google_search(...)
3. Fluent adder on an agent              - agent.add_tool.wikipedia(...)
Offline checks run first (no network). If VECTORSHIFT_API_KEY is set, the example also saves the agent and deletes it to confirm the backend accepts the payload.
from __future__ import annotations

import os

from vectorshift.agent import Agent, AgentTools, AgentType, LlmInfo, MemoryConfig
from vectorshift.agent.tool import ToolApprovalConfig, ToolInput, ToolInputType
from vectorshift.agent.tools import ExaAiTool


EXPECTED = {
    "exa_ai": ToolApprovalConfig.REQUIRES_APPROVAL,
    "google_search": ToolApprovalConfig.LET_AGENT_DECIDE,
    "wikipedia": ToolApprovalConfig.AUTO_RUN,
}


def build_agent() -> Agent:
    search = ExaAiTool(
        query=ToolInput(type=ToolInputType.DYNAMIC, description="Search query"),
        approval_config=EXPECTED["exa_ai"],
    )

    google = AgentTools.google_search(
        query=ToolInput(type=ToolInputType.DYNAMIC, description="Search query"),
        num_results=5,
        approval_config=EXPECTED["google_search"],
    )

    agent = Agent(
        id="approval-demo",
        name="Approval demo assistant",
        agent_type=AgentType.CONVERSATIONAL,
        llm_info=LlmInfo(provider="openai", model_id="gpt-4o"),
        tools=[search, google],
        instructions="Use web search when the user asks about current events.",
        memory_config=MemoryConfig(enable_session_memory=True),
    )

    agent.add_tool.wikipedia(
        query=ToolInput(type=ToolInputType.DYNAMIC, description="Topic to look up"),
        approval_config=EXPECTED["wikipedia"],
    )

    return agent


def main() -> None:
    agent = build_agent()

    print("In-memory tool values:")
    by_type = {t.tool_type: t for t in agent.tools}
    for tool_type, expected in EXPECTED.items():
        actual = by_type[tool_type].approval_config
        assert actual == expected, f"{tool_type}: expected {expected}, got {actual}"
        print(f"  [OK] {tool_type:20s} approval_config = {actual}")

    # Reach into _serialize_tools to show exactly what save() puts on the wire —
    # the backend parser expects approval_config at the top of each tool dict,
    # not nested under 'value' or 'inputs'.
    print("\nSerialized payload (what save() sends to the backend):")
    serialized = Agent._serialize_tools(agent.tools)
    for entry in serialized.values():
        assert "approval_config" not in entry["value"]
        assert "approval_config" not in entry["value"]["inputs"]
        print(
            f"  {entry['value']['node_type']:20s}"
            f" approval_config = {entry['approval_config']!r}"
        )

    if not os.environ.get("VECTORSHIFT_API_KEY"):
        print("\nVECTORSHIFT_API_KEY not set - skipping backend round-trip.")
        return

    print("\nSaving agent to verify the backend accepts the payload...")
    agent.save()
    print(f"  Saved agent id={agent.id}")

    agent.delete()
    print("  Deleted agent.")


if __name__ == "__main__":
    main()
Source: examples/agents/16_tool_approval_config.py in the SDK repo.