Use this file to discover all available pages before exploring further.
What this builds. A conversational agent with three tools, each gated by a different ToolApprovalConfig value, declared three different ways.
You’ll end up with. Printed in-memory values, the exact serialized save-payload the backend will receive, and (with a key set) a successful save + delete round-trip.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 annotationsimport osfrom vectorshift.agent import Agent, AgentTools, AgentType, LlmInfo, MemoryConfigfrom vectorshift.agent.tool import ToolApprovalConfig, ToolInput, ToolInputTypefrom vectorshift.agent.tools import ExaAiToolEXPECTED = { "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 agentdef 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()
In-memory tool values: [OK] exa_ai approval_config = ToolApprovalConfig.REQUIRES_APPROVAL [OK] google_search approval_config = ToolApprovalConfig.LET_AGENT_DECIDE [OK] wikipedia approval_config = ToolApprovalConfig.AUTO_RUNSerialized payload (what save() sends to the backend): exa_ai approval_config = 'requires_approval' google_search approval_config = 'let_agent_decide' wikipedia approval_config = 'auto_run'Saving agent to verify the backend accepts the payload... Saved agent id=... Deleted agent.
The serialized block is the load-bearing check: approval_config sits at the top of each tool dict (not nested under value or inputs), which is what the backend parser expects.