@@ -48,18 +48,84 @@ class ScratchpadState(TypedDict):
4848 messages : Annotated [List , add_messages ]
4949
5050
51- # Create OpenAI LLM with tools
51+ # Mock LLM for fallback when OpenAI key is not available
52+ class MockLLM :
53+ """Mock LLM that simulates tool calls for demonstration."""
54+
55+ def invoke (self , messages ):
56+ """Mock LLM that generates tool calls based on message content."""
57+ last_message = messages [- 1 ]
58+
59+ # If the last message is a ToolMessage, respond normally without tools
60+ if isinstance (last_message , ToolMessage ):
61+ return AIMessage (content = "Task completed successfully!" )
62+
63+ # Only generate tool calls for HumanMessage
64+ if isinstance (last_message , HumanMessage ):
65+ content = last_message .content .lower ()
66+
67+ if "write" in content and "scratchpad" in content :
68+ # Extract content to write
69+ notes = content .split (":" )[- 1 ].strip () if ":" in content else content .replace ("write to scratchpad" , "" ).strip ()
70+ return AIMessage (
71+ content = "I'll write that to the scratchpad for you." ,
72+ tool_calls = [{
73+ "name" : "WriteToScratchpad" ,
74+ "args" : {"notes" : notes },
75+ "id" : f"call_{ datetime .now ().timestamp ()} "
76+ }]
77+ )
78+ elif "read" in content and "scratchpad" in content :
79+ return AIMessage (
80+ content = "Let me read from the scratchpad." ,
81+ tool_calls = [{
82+ "name" : "ReadFromScratchpad" ,
83+ "args" : {},
84+ "id" : f"call_{ datetime .now ().timestamp ()} "
85+ }]
86+ )
87+ elif "search" in content :
88+ # Mock search query
89+ query = content .replace ("search" , "" ).strip ()
90+ return AIMessage (
91+ content = f"I'll search for: { query } " ,
92+ tool_calls = [{
93+ "name" : "tavily_search" ,
94+ "args" : {"query" : query },
95+ "id" : f"call_{ datetime .now ().timestamp ()} "
96+ }]
97+ )
98+
99+ return AIMessage (content = "I understand. How can I help you with writing to or reading from the scratchpad, or searching for information?" )
100+
101+
102+ # Create LLM with tools (OpenAI or fallback to mock)
52103def create_llm_with_tools ():
53- """Create OpenAI LLM bound with tools."""
54- llm = ChatOpenAI (
55- model = "gpt-4o-mini" , # Use the more affordable mini model
56- temperature = 0.1 ,
57- max_tokens = 150
58- )
59-
60- # Bind tools to the LLM
61- tools = [WriteToScratchpad , ReadFromScratchpad , tavily_search ]
62- return llm .bind_tools (tools )
104+ """Create LLM bound with tools. Uses OpenAI if API key is available, otherwise falls back to mock."""
105+ import os
106+
107+ # Check if OpenAI API key is available
108+ if os .getenv ("OPENAI_API_KEY" ):
109+ try :
110+ llm = ChatOpenAI (
111+ model = "gpt-4o-mini" , # Use the more affordable mini model
112+ temperature = 0.1 ,
113+ max_tokens = 150
114+ )
115+
116+ # Bind tools to the LLM
117+ tools = [WriteToScratchpad , ReadFromScratchpad , tavily_search ]
118+ print ("🤖 Using OpenAI GPT-4o-mini" )
119+ return llm .bind_tools (tools )
120+ except Exception as e :
121+ print (f"⚠️ OpenAI initialization failed: { e } " )
122+ print ("🔄 Falling back to mock LLM" )
123+ else :
124+ print ("⚠️ No OpenAI API key found (OPENAI_API_KEY environment variable)" )
125+ print ("🔄 Using mock LLM for demonstration" )
126+
127+ # Fallback to mock LLM
128+ return MockLLM ()
63129
64130
65131# Mock tools for demonstration
0 commit comments