| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118 |
- """End-to-end test: load config, call LLM, run a tool, get final answer."""
- import asyncio
- import io
- import sys
- from pathlib import Path
- # Fix Windows GBK encoding for emoji output
- sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8", errors="replace")
- sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding="utf-8", errors="replace")
- async def main():
- # 1. Load config
- from toyclaw.config import load_config
- cfg = load_config()
- print(f"[config] model={cfg.model}, api_base={cfg.api_base}")
- print(f"[config] workspace={cfg.workspace}")
- # 2. Test provider directly — simple chat (no tools)
- from toyclaw.provider import OpenAIProvider
- provider = OpenAIProvider(
- api_key=cfg.api_key,
- api_base=cfg.api_base,
- default_model=cfg.model,
- )
- print("\n--- Test 1: Simple chat (no tools) ---")
- resp = await provider.chat(
- messages=[
- {"role": "system", "content": "You are a helpful assistant. Reply concisely."},
- {"role": "user", "content": "What is 2+3? Just the number."},
- ],
- )
- print(f"[LLM] content={resp.content!r}")
- print(f"[LLM] finish_reason={resp.finish_reason}, tool_calls={len(resp.tool_calls)}")
- assert resp.content and "5" in resp.content, f"Expected '5' in response, got: {resp.content}"
- print("PASS: Simple chat works!\n")
- # 3. Test with tools — LLM should call a tool
- print("--- Test 2: Chat with tools (expect tool call) ---")
- from toyclaw.tools.base import ToolRegistry
- from toyclaw.tools.builtin import ReadFileTool, WriteFileTool, ListDirTool, ShellTool
- ws = cfg.workspace
- reg = ToolRegistry()
- reg.register(ReadFileTool(workspace=ws))
- reg.register(WriteFileTool(workspace=ws))
- reg.register(ListDirTool(workspace=ws))
- reg.register(ShellTool(workspace=ws))
- schemas = reg.get_definitions()
- print(f"[tools] {len(schemas)} tools registered: {reg.names}")
- resp2 = await provider.chat(
- messages=[
- {"role": "system", "content": "You are an AI assistant with tools. Use them when needed."},
- {"role": "user", "content": "Please list the files in the current workspace directory."},
- ],
- tools=schemas,
- )
- print(f"[LLM] content={resp2.content!r}")
- print(f"[LLM] tool_calls={[(tc.name, tc.arguments) for tc in resp2.tool_calls]}")
- if resp2.has_tool_calls:
- print("PASS: LLM generated tool calls!")
- # Execute the tool call
- for tc in resp2.tool_calls:
- result = await reg.execute(tc.name, tc.arguments)
- print(f"[tool:{tc.name}] result={result[:200]!r}")
- else:
- print("INFO: LLM responded directly without tool calls (acceptable)")
- # 4. Full agent loop test (via agent.py)
- print("\n--- Test 3: Full Agent.process() ---")
- from toyclaw.agent import Agent
- from toyclaw.session import SessionManager
- sess_mgr = SessionManager(ws)
- agent = Agent(
- provider=provider,
- tools=reg,
- workspace=ws,
- session_mgr=sess_mgr,
- max_iterations=cfg.max_iterations,
- )
- # Simple question — no tool needed
- answer = await agent.process(
- content="Hi! What's the capital of France? One word answer.",
- session_key="e2e_test",
- )
- print(f"[agent] answer={answer!r}")
- assert answer and len(answer) > 0, "Agent returned empty answer"
- print("PASS: Agent.process() works!\n")
- # 5. Agent with tool usage — ask it to create a file
- print("--- Test 4: Agent creates a file via tool ---")
- answer2 = await agent.process(
- content="Create a file called 'e2e_test.txt' in the workspace with content 'Hello from toyclaw!'. Then confirm what you wrote.",
- session_key="e2e_test",
- )
- print(f"[agent] answer={answer2[:300]!r}")
- test_file = ws / "e2e_test.txt"
- if test_file.exists():
- content = test_file.read_text(encoding="utf-8")
- print(f"[file] {test_file} content={content!r}")
- assert "Hello from toyclaw" in content
- print("PASS: Agent successfully created file via tool!")
- test_file.unlink() # cleanup
- else:
- print("WARN: File not created (agent may have used different path)")
- print("\n" + "=" * 50)
- print("All end-to-end tests completed!")
- if __name__ == "__main__":
- asyncio.run(main())
|