Skip to content

Commit d92d816

Browse files
[ai] chore: Add more integration tests
1 parent 3ded6d5 commit d92d816

File tree

3 files changed

+435
-0
lines changed

3 files changed

+435
-0
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@ poetry.toml
55
.ruff_cache/
66
.vscode
77
.env
8+
.env.test.local
89
tests/assets/*.jsonl
910
tests/assets/*.parquet

tests/integration/test_agents.py

Lines changed: 329 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,329 @@
1+
from humanloop.client import Humanloop
2+
from humanloop.types.chat_message import ChatMessage
3+
4+
from tests.integration.conftest import TestIdentifiers
5+
6+
7+
def test_agents_call(
8+
humanloop_test_client: Humanloop,
9+
prompt: TestIdentifiers,
10+
test_prompt_config: TestIdentifiers,
11+
) -> None:
12+
# Create a test agent configuration
13+
agent_config = {
14+
"provider": test_prompt_config['provider'],
15+
"model": test_prompt_config['model'],
16+
"temperature": test_prompt_config['temperature'],
17+
"template": test_prompt_config['template'],
18+
"max_iterations": 1,
19+
}
20+
21+
# Define a simple agent path for testing
22+
agent_path = "test_agent"
23+
24+
# Test with a simple question
25+
response = humanloop_test_client.agents.call( # type: ignore [attr-defined]
26+
path=agent_path,
27+
agent=agent_config,
28+
inputs={"question": "What is the capital of France?"},
29+
)
30+
31+
assert response is not None
32+
assert response.log_id is not None
33+
assert response.output_message is not None
34+
assert "Paris" in response.output_message.content
35+
36+
37+
def test_agents_call_stream(
38+
humanloop_test_client: Humanloop,
39+
prompt: TestIdentifiers,
40+
test_prompt_config: TestIdentifiers,
41+
) -> None:
42+
# Create a test agent configuration
43+
agent_config = {
44+
"provider": test_prompt_config['provider'],
45+
"model": test_prompt_config['model'],
46+
"temperature": test_prompt_config['temperature'],
47+
"template": test_prompt_config['template'],
48+
"max_iterations": 1,
49+
}
50+
51+
# Define a simple agent path for testing
52+
agent_path = "test_agent_stream"
53+
54+
# Test with streaming response
55+
response = humanloop_test_client.agents.call_stream( # type: ignore [attr-defined]
56+
path=agent_path,
57+
agent=agent_config,
58+
inputs={"question": "What is the capital of France?"},
59+
)
60+
61+
output = ""
62+
log_id = None
63+
64+
for chunk in response:
65+
assert chunk is not None
66+
if not log_id and chunk.log_id:
67+
log_id = chunk.log_id
68+
69+
if chunk.payload and chunk.payload.output:
70+
output += chunk.payload.output
71+
72+
assert log_id is not None
73+
assert "Paris" in output
74+
75+
76+
def test_agents_call_with_different_questions(
77+
humanloop_test_client: Humanloop,
78+
prompt: TestIdentifiers,
79+
test_prompt_config: TestIdentifiers,
80+
) -> None:
81+
# Create a test agent configuration
82+
agent_config = {
83+
"provider": test_prompt_config['provider'],
84+
"model": test_prompt_config['model'],
85+
"temperature": test_prompt_config['temperature'],
86+
"template": test_prompt_config['template'],
87+
"max_iterations": 1,
88+
}
89+
90+
agent_path = "test_agent_questions"
91+
92+
# Test with a math question
93+
response = humanloop_test_client.agents.call( # type: ignore [attr-defined]
94+
path=agent_path,
95+
agent=agent_config,
96+
inputs={"question": "What is 5 + 7?"},
97+
)
98+
99+
assert response is not None
100+
assert response.output_message is not None
101+
assert "12" in response.output_message.content
102+
103+
# Test with a different geography question
104+
response = humanloop_test_client.agents.call( # type: ignore [attr-defined]
105+
path=agent_path,
106+
agent=agent_config,
107+
inputs={"question": "What is the capital of Japan?"},
108+
)
109+
110+
assert response is not None
111+
assert response.output_message is not None
112+
assert "Tokyo" in response.output_message.content
113+
114+
115+
def test_agents_call_with_modified_config(
116+
humanloop_test_client: Humanloop,
117+
prompt: TestIdentifiers,
118+
test_prompt_config: TestIdentifiers,
119+
) -> None:
120+
# Create a test agent configuration with modified temperature
121+
agent_config = {
122+
"provider": test_prompt_config['provider'],
123+
"model": test_prompt_config['model'],
124+
"temperature": 0.1, # Lower temperature
125+
"template": test_prompt_config['template'],
126+
"max_iterations": 1,
127+
}
128+
129+
agent_path = "test_agent_modified"
130+
131+
response = humanloop_test_client.agents.call( # type: ignore [attr-defined]
132+
path=agent_path,
133+
agent=agent_config,
134+
inputs={"question": "What is the capital of France?"},
135+
)
136+
137+
assert response is not None
138+
assert response.output_message is not None
139+
assert "Paris" in response.output_message.content
140+
141+
142+
def test_agents_log(
143+
humanloop_test_client: Humanloop,
144+
prompt: TestIdentifiers,
145+
test_prompt_config: TestIdentifiers,
146+
) -> None:
147+
# Create a test agent configuration
148+
agent_config = {
149+
"provider": test_prompt_config['provider'],
150+
"model": test_prompt_config['model'],
151+
"temperature": test_prompt_config['temperature'],
152+
"template": test_prompt_config['template'],
153+
"max_iterations": 1,
154+
}
155+
156+
agent_path = "test_agent_log"
157+
158+
# Test logging agent interaction
159+
response = humanloop_test_client.agents.log( # type: ignore [attr-defined]
160+
path=agent_path,
161+
agent=agent_config,
162+
messages=[{"role": "user", "content": "Hello"}],
163+
output="Hello! How can I assist you today?",
164+
)
165+
166+
assert response is not None
167+
assert response.id is not None
168+
# For CreateAgentLogResponse, the id is used instead of log_id
169+
170+
171+
def test_agents_upsert(
172+
humanloop_test_client: Humanloop,
173+
sdk_test_dir: str,
174+
) -> None:
175+
agent_path = f"{sdk_test_dir}/test_agent_upsert"
176+
177+
# Create a test agent config for upsert
178+
agent_config = {
179+
"provider": "openai",
180+
"model": "gpt-4o-mini",
181+
"temperature": 0.7,
182+
"template": [
183+
{
184+
"role": "system",
185+
"content": "You are a helpful assistant specialized in answering geography questions.",
186+
}
187+
],
188+
"max_iterations": 3,
189+
}
190+
191+
# Test upserting an agent
192+
response = humanloop_test_client.agents.upsert( # type: ignore [attr-defined]
193+
path=agent_path,
194+
**agent_config,
195+
)
196+
197+
assert response is not None
198+
assert response.id is not None
199+
assert response.path == agent_path
200+
201+
# Clean up after test
202+
humanloop_test_client.agents.delete(id=response.id)
203+
204+
205+
def test_agents_call_with_tool(
206+
humanloop_test_client: Humanloop,
207+
prompt: TestIdentifiers,
208+
test_prompt_config: TestIdentifiers,
209+
) -> None:
210+
# Define a simple tool in the inline format
211+
calculator_tool = {
212+
"type": "inline",
213+
"json_schema": {
214+
"name": "calculator",
215+
"description": "Calculate a math expression",
216+
"parameters": {
217+
"type": "object",
218+
"properties": {
219+
"expression": {
220+
"type": "string",
221+
"description": "The math expression to calculate"
222+
}
223+
},
224+
"required": ["expression"]
225+
}
226+
}
227+
}
228+
229+
# Create a test agent configuration with tools included
230+
agent_config = {
231+
"provider": test_prompt_config['provider'],
232+
"model": test_prompt_config['model'],
233+
"temperature": test_prompt_config['temperature'],
234+
"template": test_prompt_config['template'],
235+
"max_iterations": 1,
236+
"tools": [calculator_tool], # Include tools in agent config
237+
}
238+
239+
agent_path = "test_agent_with_tool"
240+
241+
# Test with tool
242+
response = humanloop_test_client.agents.call( # type: ignore [attr-defined]
243+
path=agent_path,
244+
agent=agent_config,
245+
inputs={"question": "Calculate 25 × 4"},
246+
tool_choice={"type": "function", "function": {"name": "calculator"}}
247+
)
248+
249+
assert response is not None
250+
assert response.output_message is not None
251+
# The model should have made a tool call
252+
assert hasattr(response.output_message, 'tool_calls') and response.output_message.tool_calls
253+
for tool_call in response.output_message.tool_calls:
254+
if tool_call.function.name == "calculator":
255+
assert "expression" in tool_call.function.arguments
256+
257+
258+
def test_agents_continue_call(
259+
humanloop_test_client: Humanloop,
260+
prompt: TestIdentifiers,
261+
test_prompt_config: TestIdentifiers,
262+
) -> None:
263+
# Define a simple tool in the inline format
264+
calculator_tool = {
265+
"type": "inline",
266+
"json_schema": {
267+
"name": "calculator",
268+
"description": "Calculate a math expression",
269+
"parameters": {
270+
"type": "object",
271+
"properties": {
272+
"expression": {
273+
"type": "string",
274+
"description": "The math expression to calculate"
275+
}
276+
},
277+
"required": ["expression"]
278+
}
279+
}
280+
}
281+
282+
# Create a test agent configuration with tools included
283+
agent_config = {
284+
"provider": test_prompt_config['provider'],
285+
"model": test_prompt_config['model'],
286+
"temperature": test_prompt_config['temperature'],
287+
"template": test_prompt_config['template'],
288+
"max_iterations": 2, # Need at least 2 for continue call
289+
"tools": [calculator_tool], # Include tools in agent config
290+
}
291+
292+
agent_path = "test_agent_continue"
293+
294+
# First make an initial call that will use a tool
295+
initial_response = humanloop_test_client.agents.call( # type: ignore [attr-defined]
296+
path=agent_path,
297+
agent=agent_config,
298+
inputs={"question": "Calculate 25 × 4"},
299+
tool_choice={"type": "function", "function": {"name": "calculator"}}
300+
)
301+
302+
assert initial_response is not None
303+
assert initial_response.log_id is not None
304+
305+
# Get the tool call from output_message
306+
assert hasattr(initial_response.output_message, 'tool_calls') and initial_response.output_message.tool_calls
307+
tool_call = None
308+
for tc in initial_response.output_message.tool_calls:
309+
if tc.function.name == "calculator":
310+
tool_call = tc
311+
break
312+
313+
assert tool_call is not None
314+
assert tool_call.id is not None
315+
316+
# Now continue the call with a tool response
317+
continue_response = humanloop_test_client.agents.continue_call( # type: ignore [attr-defined]
318+
log_id=initial_response.log_id,
319+
messages=[{
320+
"role": "tool",
321+
"content": '{"result": 100}',
322+
"tool_call_id": tool_call.id
323+
}],
324+
)
325+
326+
assert continue_response is not None
327+
assert continue_response.log_id == initial_response.log_id
328+
assert continue_response.output_message is not None
329+
assert "100" in continue_response.output_message.content

0 commit comments

Comments
 (0)