@aurite-ai/kai 0.2.0-dev.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/README.md +190 -0
  2. package/dist/kai-mcp.cjs +1652 -0
  3. package/dist/kai-mcp.cjs.map +7 -0
  4. package/dist/templates/copilot-configs/claude-code/.claude/CLAUDE.md +272 -0
  5. package/dist/templates/copilot-configs/claude-code/.claude/agents/architect.md +133 -0
  6. package/dist/templates/copilot-configs/claude-code/.claude/agents/implementer.md +88 -0
  7. package/dist/templates/copilot-configs/claude-code/.claude/settings.json +87 -0
  8. package/dist/templates/copilot-configs/claude-code/.claude/skills/documentation/SKILL.md +54 -0
  9. package/dist/templates/copilot-configs/claude-code/.claude/skills/verification/SKILL.md +125 -0
  10. package/dist/templates/frameworks/langgraph/README.md +118 -0
  11. package/dist/templates/frameworks/langgraph/main.py +97 -0
  12. package/dist/templates/frameworks/langgraph/pyproject.toml +29 -0
  13. package/dist/templates/frameworks/langgraph/src/agent/__init__.py +31 -0
  14. package/dist/templates/frameworks/langgraph/src/agent/graph.py +257 -0
  15. package/dist/templates/frameworks/langgraph/src/agent/state.py +65 -0
  16. package/dist/templates/frameworks/langgraph/src/agent/tools.py +30 -0
  17. package/dist/templates/frameworks/openai/README.md +131 -0
  18. package/dist/templates/frameworks/openai/main.py +80 -0
  19. package/dist/templates/frameworks/openai/pyproject.toml +28 -0
  20. package/dist/templates/frameworks/openai/src/agent/__init__.py +18 -0
  21. package/dist/templates/frameworks/openai/src/agent/agents.py +122 -0
  22. package/dist/templates/frameworks/openai/src/agent/tools.py +100 -0
  23. package/dist/templates/index.d.ts +85 -0
  24. package/dist/templates/index.d.ts.map +1 -0
  25. package/dist/templates/index.js +270 -0
  26. package/dist/templates/index.js.map +1 -0
  27. package/dist/templates/knowledge-base/langgraph-best-practices.mdc +277 -0
  28. package/dist/templates/knowledge-base/openai-agents-overview.mdc +602 -0
  29. package/dist/templates/project-env +7 -0
  30. package/dist/templates/project-gitignore +26 -0
  31. package/package.json +66 -0
@@ -0,0 +1,125 @@
1
+ ---
2
+ name: verification
3
+ description: Verify agent code against organizational policies and best practices. Trigger this skill when the user says something like "verify my agent", "review agent code", "check compliance", "audit my agent", "check my agent against rules", or "validate agent implementation"
4
+ ---
5
+
6
+ # Verify Agent
7
+
8
+ ## Purpose
9
+
10
+ Verify agent code against business rules, security policies, and framework best practices from Kai's knowledge base. All analysis happens locally—code never leaves the user's machine.
11
+
12
+ ## When to Use
13
+
14
+ Trigger this skill when the user asks to:
15
+ - "verify my agent"
16
+ - "review agent code"
17
+ - "check compliance"
18
+ - "audit my agent"
19
+ - "check my agent against rules"
20
+ - "validate agent implementation"
21
+
22
+ ## Process
23
+
24
+ > **Note:** This skill assumes organizational and IT rules are already available in the conversation context from the `kai_prepare_context` call at conversation start (per CLAUDE.md rules).
25
+
26
+ ### Step 1: Load Framework Best Practices
27
+
28
+ Check the `context-guide.md` for framework-specific best practices surfaced by `kai_prepare_context`:
29
+
30
+ These files define best practices, required patterns, and anti-patterns specific to that framework. Load and reference them during verification.
31
+
32
+ If framework best practices aren't available in `context/`, use the **documentation** skill (`.claude/skills/documentation/SKILL.md`) to search for relevant framework documentation.
33
+ ### Step 2: Discover Agent Files
34
+
35
+ Locate agent implementation files in the project. Check these common locations:
36
+
37
+ **Directories:**
38
+ - `src/agent/`
39
+ - `agent/`
40
+ - `src/`
41
+ - Project root
42
+
43
+ **Key files to analyze:**
44
+ - `graph.py` - Main workflow/graph definition
45
+ - `tools.py` - Tool implementations
46
+ - `state.py` - State schema definitions
47
+ - `prompts.py` - Prompt templates
48
+ - `nodes.py` - Node function implementations
49
+ - `config.py` - Configuration and settings
50
+
51
+ Use `list_files` or similar to discover the actual structure, then read relevant files.
52
+
53
+ ### Step 3: Verify Code Against Rules
54
+
55
+ Analyze the agent code against all available rules:
56
+
57
+ 1. **Organizational rules** - Check code against company policies from conversation context
58
+ 2. **IT/Security rules** - Check code against security requirements from conversation context
59
+ 3. **Framework best practices** - Check code against patterns from the framework best practices in `context-guide.md`
60
+
61
+ For each rule, determine:
62
+ - ✅ **Pass** - Code complies with the rule
63
+ - ⚠️ **Warning** - Potential concern worth reviewing
64
+ - ❌ **Issue** - Clear violation that needs fixing
65
+
66
+ ### Step 4: Generate Report
67
+
68
+ Output a structured verification report:
69
+
70
+ ```markdown
71
+ # Agent Verification Report
72
+
73
+ **Project:** [project name or path]
74
+ **Date:** [current date]
75
+ **Files analyzed:** [list of files]
76
+
77
+ ## Summary
78
+
79
+ ✅ X checks passed | ⚠️ Y warnings | ❌ Z issues
80
+
81
+ ## Findings
82
+
83
+ ### ✅ Passing
84
+ - [Check name]: [Brief confirmation of compliance]
85
+
86
+ ### ⚠️ Warnings
87
+ - [Check name]: [Description of concern]
88
+ - **Location:** [file:line if applicable]
89
+ - **Suggestion:** [How to address]
90
+
91
+ ### ❌ Issues
92
+ - [Check name]: [Description of violation]
93
+ - **Location:** [file:line]
94
+ - **Rule:** [Which rule this violates]
95
+ - **Fix:** [Specific remediation steps]
96
+
97
+ ## Recommendations
98
+
99
+ 1. [Priority recommendation based on findings]
100
+ 2. [Additional improvements]
101
+ ```
102
+
103
+ ### Step 5: Export Report (Optional)
104
+
105
+ After presenting the report, ask the user:
106
+
107
+ > Would you like to save this verification report to a file?
108
+
109
+ If the user confirms, save the report to:
110
+
111
+ ```
112
+ reports/verification/YYYY-MM-DD_HH-MM-SS.md
113
+ ```
114
+
115
+ - Use the current date and time for the filename (e.g., `2026-02-10_15-28-32.md`)
116
+ - Create the `reports/verification/` directory if it doesn't exist
117
+ - Confirm the save location to the user after writing
118
+
119
+ ## Notes
120
+
121
+ - **Privacy first:** All code analysis happens locally. Nothing is sent to external services.
122
+ - **Rules come from Kai:** The knowledge base provides organization-specific rules. Apply them as written.
123
+ - **Framework best practices:** Don't duplicate framework best practices here—reference files in `context-guide.md`.
124
+ - **Be specific:** Include file names and line numbers when reporting issues.
125
+ - **Explain the "why":** Help developers understand why each rule matters.
@@ -0,0 +1,118 @@
1
+ # LangGraph Agent Framework
2
+
3
+ A minimal but functional LangGraph Python project demonstrating core agent patterns.
4
+
5
+ ## Overview
6
+
7
+ This scaffold provides a working LangGraph agent with:
8
+ - State management using TypedDict
9
+ - Tool calling with the ReAct pattern
10
+ - Conditional routing based on tool calls
11
+ - Well-commented code for learning
12
+
13
+ ## Requirements
14
+
15
+ - Python 3.11+
16
+ - `uv` (recommended) or `pip`
17
+
18
+ ## Setup
19
+
20
+ ### Using uv (Recommended)
21
+
22
+ ```bash
23
+ # Create and activate virtual environment
24
+ uv venv
25
+ source .venv/bin/activate # On Windows: .venv\Scripts\activate
26
+
27
+ # Install dependencies
28
+ uv pip install -e .
29
+ ```
30
+
31
+ ### Using pip
32
+
33
+ ```bash
34
+ # Create and activate virtual environment
35
+ python -m venv .venv
36
+ source .venv/bin/activate # On Windows: .venv\Scripts\activate
37
+
38
+ # Install dependencies
39
+ pip install -e .
40
+ ```
41
+
42
+ ## Configuration
43
+
44
+ Set your API key as an environment variable:
45
+
46
+ ```bash
47
+ # For Anthropic (default)
48
+ export ANTHROPIC_API_KEY="your-key-here"
49
+
50
+ # Or for OpenAI
51
+ export OPENAI_API_KEY="your-key-here"
52
+ ```
53
+
54
+ ## Running the Agent
55
+
56
+ ```bash
57
+ # Run with default example
58
+ python main.py
59
+
60
+ # Or import and use programmatically
61
+ python -c "from src.agent import run_agent; print(run_agent('Your prompt here'))"
62
+ ```
63
+
64
+ ## Project Structure
65
+
66
+ ```
67
+ langgraph/
68
+ ├── README.md # This file
69
+ ├── pyproject.toml # Project configuration
70
+ ├── main.py # Entry point
71
+ └── src/
72
+ └── agent/
73
+ ├── __init__.py # Package exports
74
+ ├── state.py # State TypedDict definition
75
+ ├── tools.py # Tool definitions (implement your scenario tools here)
76
+ └── graph.py # Main StateGraph definition
77
+ ```
78
+
79
+ ## Extending the Agent
80
+
81
+ ### Adding New Tools
82
+
83
+ 1. Define your tool in `src/agent/tools.py`:
84
+
85
+ ```python
86
+ @tool
87
+ def my_new_tool(param: str) -> str:
88
+ """Description of what the tool does.
89
+
90
+ Args:
91
+ param: Description of the parameter
92
+ """
93
+ return "result"
94
+ ```
95
+
96
+ 2. Add it to the `tools` list in the same file.
97
+
98
+ ### Modifying State
99
+
100
+ Edit `src/agent/state.py` to add new state fields:
101
+
102
+ ```python
103
+ class AgentState(TypedDict):
104
+ messages: Annotated[list[AnyMessage], operator.add]
105
+ my_new_field: str # Add new fields here
106
+ ```
107
+
108
+ ### Changing the Graph Structure
109
+
110
+ Edit `src/agent/graph.py` to:
111
+ - Add new nodes with `builder.add_node()`
112
+ - Add new edges with `builder.add_edge()` or `builder.add_conditional_edges()`
113
+
114
+ ## Learning Resources
115
+
116
+ - [LangGraph Documentation](https://langchain-ai.github.io/langgraph/)
117
+ - [LangChain Tools Guide](https://python.langchain.com/docs/modules/tools/)
118
+ - See `.claude/rules/langgraph.md` for patterns and best practices
@@ -0,0 +1,97 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ LangGraph Agent Entry Point
4
+
5
+ This script demonstrates how to run the LangGraph agent with example queries.
6
+ It shows both interactive conversation and programmatic usage patterns.
7
+
8
+ Usage:
9
+ # Run with default examples
10
+ python main.py
11
+
12
+ # Import and use programmatically
13
+ from src.agent import run_agent
14
+ result = run_agent("What is 10 + 5?")
15
+ """
16
+
17
+ import sys
18
+
19
+ from langchain_core.messages import HumanMessage
20
+
21
+
22
+ def main():
23
+ """Run the agent with example queries."""
24
+ # Import here to catch any configuration errors early
25
+ try:
26
+ from src.agent import create_agent, run_agent
27
+ except ValueError as e:
28
+ print(f"Configuration error: {e}")
29
+ print("\nPlease set your API key:")
30
+ print(" export ANTHROPIC_API_KEY='your-key-here'")
31
+ print(" # or")
32
+ print(" export OPENAI_API_KEY='your-key-here'")
33
+ sys.exit(1)
34
+
35
+ print("=" * 50)
36
+ print("LangGraph Agent Demo")
37
+ print("=" * 50)
38
+
39
+ # Example queries that demonstrate tool usage
40
+ example_queries = [
41
+ "What is 15 + 27?",
42
+ "Calculate 8 * 12",
43
+ "What is 100 divided by 4?",
44
+ ]
45
+
46
+ print("\nRunning example queries...\n")
47
+
48
+ for query in example_queries:
49
+ print(f"User: {query}")
50
+ try:
51
+ response = run_agent(query)
52
+ print(f"Agent: {response}\n")
53
+ except Exception as e:
54
+ print(f"Error: {e}\n")
55
+
56
+ # Demonstrate more detailed usage with state inspection
57
+ print("-" * 50)
58
+ print("Detailed execution example:")
59
+ print("-" * 50)
60
+
61
+ agent = create_agent()
62
+
63
+ # Run with full state tracking
64
+ initial_state = {
65
+ "messages": [HumanMessage(content="What is 25 multiplied by 4?")],
66
+ "tool_call_count": 0,
67
+ }
68
+
69
+ print(f"\nInitial query: {initial_state['messages'][0].content}")
70
+
71
+ # Execute the agent
72
+ final_state = agent.invoke(initial_state)
73
+
74
+ # Show the conversation flow
75
+ print("\nConversation flow:")
76
+ for i, msg in enumerate(final_state["messages"]):
77
+ msg_type = type(msg).__name__
78
+ # Handle content that may be a string or list (e.g., tool call blocks)
79
+ raw_content = msg.content
80
+ if isinstance(raw_content, list):
81
+ content = (
82
+ str(raw_content)[:100] + "..."
83
+ if len(str(raw_content)) > 100
84
+ else str(raw_content)
85
+ )
86
+ else:
87
+ content = (
88
+ raw_content[:100] + "..." if len(raw_content) > 100 else raw_content
89
+ )
90
+ print(f" {i + 1}. [{msg_type}] {content}")
91
+
92
+ print(f"\nTotal tool calls: {final_state['tool_call_count']}")
93
+ print(f"Final answer: {final_state['messages'][-1].content}")
94
+
95
+
96
+ if __name__ == "__main__":
97
+ main()
@@ -0,0 +1,29 @@
1
+ [project]
2
+ name = "langgraph-agent"
3
+ version = "0.1.0"
4
+ description = "A minimal LangGraph agent scaffold for learning and testing"
5
+ readme = "README.md"
6
+ requires-python = ">=3.11"
7
+ dependencies = [
8
+ "langgraph>=0.2.0",
9
+ "langchain>=0.3.0",
10
+ "langchain-anthropic>=0.2.0",
11
+ "langchain-openai>=0.2.0",
12
+ ]
13
+
14
+ [project.optional-dependencies]
15
+ dev = [
16
+ "pytest>=8.0.0",
17
+ "pytest-asyncio>=0.24.0",
18
+ ]
19
+
20
+ [build-system]
21
+ requires = ["hatchling"]
22
+ build-backend = "hatchling.build"
23
+
24
+ [tool.hatch.build.targets.wheel]
25
+ packages = ["src/agent"]
26
+
27
+ [tool.pytest.ini_options]
28
+ asyncio_mode = "auto"
29
+ testpaths = ["tests"]
@@ -0,0 +1,31 @@
1
+ """
2
+ LangGraph Agent Package
3
+
4
+ This package provides a minimal but functional LangGraph agent that demonstrates
5
+ core patterns including state management, tool calling, and conditional routing.
6
+
7
+ Example usage:
8
+ from agent import run_agent, create_agent
9
+
10
+ # Quick run with a message
11
+ result = run_agent("What is 15 + 27?")
12
+ print(result)
13
+
14
+ # Or get the compiled graph for more control
15
+ agent = create_agent()
16
+ result = agent.invoke({"messages": [HumanMessage(content="Hello")]})
17
+ """
18
+
19
+ from .graph import create_agent, run_agent
20
+ from .state import AgentState
21
+ from .tools import add, divide, multiply, tools
22
+
23
+ __all__ = [
24
+ "create_agent",
25
+ "run_agent",
26
+ "AgentState",
27
+ "tools",
28
+ "add",
29
+ "multiply",
30
+ "divide",
31
+ ]
@@ -0,0 +1,257 @@
1
+ """
2
+ LangGraph Agent Definition
3
+
4
+ This module defines the main StateGraph for the agent. It implements a standard
5
+ ReAct-style (Reasoning + Acting) agent pattern where the LLM can decide to
6
+ either respond directly or call tools to gather information.
7
+
8
+ Key Concepts:
9
+ - StateGraph: The container for nodes and edges
10
+ - Nodes: Functions that perform work (LLM calls, tool execution)
11
+ - Edges: Connections that determine flow between nodes
12
+ - Conditional edges: Dynamic routing based on state
13
+
14
+ Graph Structure:
15
+ START → call_model → [should_continue] → execute_tools → call_model
16
+ ↘ ↗
17
+ → END (if no tool calls)
18
+ """
19
+
20
+ import os
21
+ from typing import Literal
22
+
23
+ from langchain_core.messages import AIMessage, HumanMessage, SystemMessage, ToolMessage
24
+ from langgraph.graph import END, START, StateGraph
25
+
26
+ from .state import AgentState
27
+ from .tools import tools, tools_by_name
28
+
29
+
30
+ def get_model():
31
+ """
32
+ Initialize the LLM with tool binding.
33
+
34
+ This function creates the chat model and binds the available tools to it.
35
+ The model will include tool definitions in its context, allowing it to
36
+ decide when and how to call tools.
37
+
38
+ Returns:
39
+ A chat model instance with tools bound.
40
+
41
+ Note:
42
+ Set ANTHROPIC_API_KEY or OPENAI_API_KEY environment variable.
43
+ Defaults to Anthropic if ANTHROPIC_API_KEY is set.
44
+ """
45
+ # Try Anthropic first (preferred), then fall back to OpenAI
46
+ if os.environ.get("ANTHROPIC_API_KEY"):
47
+ from langchain_anthropic import ChatAnthropic
48
+
49
+ model = ChatAnthropic(model="claude-sonnet-4-5-20250929", temperature=0)
50
+ elif os.environ.get("OPENAI_API_KEY"):
51
+ from langchain_openai import ChatOpenAI
52
+
53
+ model = ChatOpenAI(model="gpt-4o", temperature=0)
54
+ else:
55
+ raise ValueError(
56
+ "No API key found. Set ANTHROPIC_API_KEY or OPENAI_API_KEY environment variable."
57
+ )
58
+
59
+ # Bind tools to the model so it knows what tools are available
60
+ return model.bind_tools(tools)
61
+
62
+
63
+ # System prompt that instructs the agent on its behavior
64
+ SYSTEM_PROMPT = """You are a helpful assistant that can perform arithmetic operations.
65
+
66
+ When asked to do math, use the available tools (add, multiply, divide) to compute the answer.
67
+ Always show your work by using the appropriate tool calls.
68
+
69
+ Be concise in your responses."""
70
+
71
+
72
+ def call_model(state: AgentState) -> dict:
73
+ """
74
+ Node that calls the LLM to generate a response.
75
+
76
+ This node takes the current conversation state, prepends a system message,
77
+ and asks the LLM to generate a response. The LLM may decide to:
78
+ 1. Respond directly to the user
79
+ 2. Call one or more tools to gather information
80
+
81
+ Args:
82
+ state: Current agent state containing messages and metadata
83
+
84
+ Returns:
85
+ State update dict with the new AI message appended to messages
86
+
87
+ Note:
88
+ The return value is a partial state update. Since messages uses
89
+ operator.add as its reducer, the new message will be appended
90
+ to the existing list, not replace it.
91
+ """
92
+ model = get_model()
93
+
94
+ # Prepend system message to guide the model's behavior
95
+ messages_with_system = [SystemMessage(content=SYSTEM_PROMPT)] + state["messages"]
96
+
97
+ # Invoke the model and get response
98
+ response = model.invoke(messages_with_system)
99
+
100
+ # Return state update - the reducer will append this to existing messages
101
+ return {"messages": [response]}
102
+
103
+
104
+ def execute_tools(state: AgentState) -> dict:
105
+ """
106
+ Node that executes tool calls from the LLM's response.
107
+
108
+ When the LLM decides to call tools, this node:
109
+ 1. Extracts tool calls from the last AI message
110
+ 2. Executes each tool with the provided arguments
111
+ 3. Returns ToolMessage results for each call
112
+
113
+ Args:
114
+ state: Current agent state (last message should have tool_calls)
115
+
116
+ Returns:
117
+ State update dict with ToolMessages for each tool call result,
118
+ and incremented tool_call_count
119
+
120
+ Note:
121
+ ToolMessage includes tool_call_id to match results with calls.
122
+ This is important for the LLM to understand which result
123
+ corresponds to which tool call.
124
+ """
125
+ # Get the last message which contains the tool calls
126
+ last_message: AIMessage = state["messages"][-1]
127
+
128
+ # Execute each tool call and collect results
129
+ tool_results = []
130
+ for tool_call in last_message.tool_calls:
131
+ # Look up the tool by name
132
+ tool = tools_by_name[tool_call["name"]]
133
+
134
+ # Execute the tool with provided arguments
135
+ result = tool.invoke(tool_call["args"])
136
+
137
+ # Create a ToolMessage with the result
138
+ # tool_call_id links this result back to the specific call
139
+ tool_results.append(
140
+ ToolMessage(
141
+ content=str(result),
142
+ tool_call_id=tool_call["id"],
143
+ )
144
+ )
145
+
146
+ # Return state update with tool results and incremented count
147
+ current_count = state.get("tool_call_count", 0)
148
+ return {
149
+ "messages": tool_results,
150
+ "tool_call_count": current_count + len(tool_results),
151
+ }
152
+
153
+
154
+ def should_continue(state: AgentState) -> Literal["execute_tools", "__end__"]:
155
+ """
156
+ Conditional edge function to determine next step.
157
+
158
+ This function examines the last message to decide whether to:
159
+ - Execute tools (if the LLM made tool calls)
160
+ - End the conversation (if the LLM gave a final response)
161
+
162
+ Args:
163
+ state: Current agent state
164
+
165
+ Returns:
166
+ "execute_tools" if there are tool calls to process,
167
+ END if the conversation should terminate
168
+
169
+ Note:
170
+ This is a routing function used by add_conditional_edges().
171
+ It doesn't modify state, just returns the next node name.
172
+ """
173
+ last_message = state["messages"][-1]
174
+
175
+ # Check if the model made any tool calls
176
+ if hasattr(last_message, "tool_calls") and last_message.tool_calls:
177
+ return "execute_tools"
178
+
179
+ # No tool calls means the model is done - end the conversation
180
+ return END
181
+
182
+
183
+ def create_agent() -> StateGraph:
184
+ """
185
+ Build and compile the agent graph.
186
+
187
+ This function constructs the StateGraph by:
188
+ 1. Creating a new StateGraph with our state schema
189
+ 2. Adding nodes for each processing step
190
+ 3. Connecting nodes with edges (both direct and conditional)
191
+ 4. Compiling the graph for execution
192
+
193
+ Returns:
194
+ A compiled StateGraph ready for invocation
195
+
196
+ Graph structure:
197
+ START → call_model → [should_continue] → execute_tools → call_model
198
+ ↘ ↗
199
+ → END (if no tool calls)
200
+ """
201
+ # Step 1: Create the graph builder with our state schema
202
+ builder = StateGraph(AgentState)
203
+
204
+ # Step 2: Add nodes
205
+ # Each node is a function that takes state and returns state updates
206
+ builder.add_node("call_model", call_model)
207
+ builder.add_node("execute_tools", execute_tools)
208
+
209
+ # Step 3: Add edges
210
+ # START → call_model: Entry point
211
+ builder.add_edge(START, "call_model")
212
+
213
+ # call_model → [conditional]: Check if we need to execute tools
214
+ builder.add_conditional_edges(
215
+ "call_model",
216
+ should_continue,
217
+ # Map of return values to destination nodes
218
+ # The function returns either "execute_tools" or END
219
+ ["execute_tools", END],
220
+ )
221
+
222
+ # execute_tools → call_model: After executing tools, go back to the model
223
+ builder.add_edge("execute_tools", "call_model")
224
+
225
+ # Step 4: Compile the graph
226
+ # IMPORTANT: Must compile before the graph can be invoked
227
+ return builder.compile()
228
+
229
+
230
+ def run_agent(user_message: str) -> str:
231
+ """
232
+ Convenience function to run the agent with a single message.
233
+
234
+ Args:
235
+ user_message: The user's input message
236
+
237
+ Returns:
238
+ The agent's final response as a string
239
+
240
+ Example:
241
+ >>> result = run_agent("What is 25 * 4?")
242
+ >>> print(result)
243
+ "25 * 4 = 100"
244
+ """
245
+ agent = create_agent()
246
+
247
+ # Create initial state with the user's message
248
+ initial_state = {
249
+ "messages": [HumanMessage(content=user_message)],
250
+ "tool_call_count": 0,
251
+ }
252
+
253
+ # Run the agent to completion
254
+ final_state = agent.invoke(initial_state)
255
+
256
+ # Return the last message content (the agent's response)
257
+ return final_state["messages"][-1].content