File size: 2,867 Bytes
9936912
6be46a5
9936912
 
 
 
 
 
 
 
 
 
 
 
 
 
6be46a5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9936912
6be46a5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9936912
 
6be46a5
 
 
 
 
 
 
 
 
 
9936912
6be46a5
9936912
 
6be46a5
9936912
 
 
6be46a5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#!/usr/bin/env python3
"""Interactive CLI for ControlAI Agent with deterministic tool calling."""

from __future__ import annotations

import argparse
import sys
from pathlib import Path

PROJECT_ROOT = Path(__file__).resolve().parent
if str(PROJECT_ROOT) not in sys.path:
    sys.path.insert(0, str(PROJECT_ROOT))

from controlai_agent.orchestrator import ControlAIAgent


def main() -> int:
    parser = argparse.ArgumentParser(description="ControlAI Offline Engineering Agent CLI")
    parser.add_argument(
        "--model",
        type=str,
        default="mlx-community/Qwen3-4B-Instruct-2507-4bit",
        help="Base model path or HuggingFace repo",
    )
    parser.add_argument(
        "--adapter-path",
        type=str,
        default=None,
        help="Optional fine-tuned LoRA adapter path",
    )
    parser.add_argument(
        "--prompt",
        type=str,
        default=None,
        help="Single prompt to execute in non-interactive mode",
    )
    parser.add_argument(
        "--verbose",
        action="store_true",
        help="Print raw tool calls and intermediate steps",
    )
    args = parser.parse_args()

    print("Initializing ControlAI Agent...")
    agent = ControlAIAgent(model_path=args.model, adapter_path=args.adapter_path)
    print("ControlAI Agent initialized with deterministic control tools.")

    if args.prompt:
        result = agent.run(args.prompt, verbose=args.verbose)
        print("\n" + "=" * 50)
        print("AGENT RESPONSE:")
        print("=" * 50)
        print(result.final_response)
        if result.tool_traces:
            print("\n" + "-" * 50)
            print(f"EXECUTED TOOLS ({len(result.tool_traces)}):")
            for trace in result.tool_traces:
                print(f"  * {trace.tool_name}({trace.arguments}) -> {trace.result.get('status', 'done')}")
        return 0

    print("\n" + "=" * 60)
    print("🤖 Welcome to Control-LLM (Offline Control Engineering Agent)")
    print("=" * 60)
    print("Type your control engineering question or design problem.")
    print("Commands: 'exit' or 'quit' to end, 'verbose' to toggle tool details.\n")
    while True:
        try:
            user_input = input("\n[Engineer] > ").strip()
            if not user_input:
                continue
            if user_input.lower() in ("exit", "quit", "q"):
                break
            result = agent.run(user_input, verbose=args.verbose)
            print(f"\n[ControlAI]\n{result.final_response}")
            if result.tool_traces and not args.verbose:
                tools_used = ", ".join(t.tool_name for t in result.tool_traces)
                print(f"\n(Verified using tools: {tools_used})")
        except (KeyboardInterrupt, EOFError):
            print("\nExiting ControlAI.")
            break

    return 0


if __name__ == "__main__":
    raise SystemExit(main())