// retoor <retoor@molodetz.nl>
import "http" for Http
import "json" for Json
import "env" for Environment
import "io" for Stdin, Stdout
class Chat {
construct new(model) {
_model = model
_messages = []
_apiKey = Environment.get("OPENROUTER_API_KEY")
if (_apiKey == null || _apiKey.count == 0) {
Fiber.abort("OPENROUTER_API_KEY environment variable not set")
}
}
addSystem(content) {
_messages.add({"role": "system", "content": content})
}
send(content) {
_messages.add({"role": "user", "content": content})
var requestBody = {
"model": _model,
"messages": _messages,
"stream": false
}
var headers = {
"Authorization": "Bearer " + _apiKey,
"Content-Type": "application/json"
}
var response = Http.post("https://openrouter.ai/api/v1/chat/completions", requestBody, headers)
if (!response.ok) {
var error = "API error: %(response.statusCode)"
if (response.body.count > 0) {
var data = Json.parse(response.body)
if (data["error"] != null && data["error"]["message"] != null) {
error = data["error"]["message"]
}
}
return {"error": error}
}
var data = Json.parse(response.body)
if (data["choices"] != null && data["choices"].count > 0) {
var message = data["choices"][0]["message"]
if (message != null) {
_messages.add(message)
return {
"content": message["content"],
"model": data["model"],
"usage": data["usage"]
}
}
}
return {"error": "Invalid response format"}
}
clear() {
var system = _messages.count > 0 && _messages[0]["role"] == "system" ? _messages[0] : null
_messages = []
if (system != null) _messages.add(system)
}
model { _model }
model=(value) { _model = value }
messageCount { _messages.count }
}
var model = "x-ai/grok-code-fast-1"
var chat = Chat.new(model)
chat.addSystem("You are a helpful assistant. Be concise in your responses.")
System.print("OpenRouter Chat")
System.print("Model: %(model)")
System.print("Commands: /quit, /clear, /model <name>, /history")
System.print("-" * 50)
while (true) {
System.write("\nYou: ")
Stdout.flush()
var input = Stdin.readLine()
if (input == null || input.trim() == "/quit" || input.trim() == "/exit") {
System.print("Goodbye!")
break
}
input = input.trim()
if (input.count == 0) continue
if (input == "/clear") {
chat.clear()
System.print("[Conversation cleared]")
continue
}
if (input == "/history") {
System.print("[%(chat.messageCount) messages in history]")
continue
}
if (input.startsWith("/model ")) {
var newModel = input[7..-1].trim()
if (newModel.count > 0) {
chat.model = newModel
System.print("[Model changed to: %(newModel)]")
}
continue
}
if (input.startsWith("/")) {
System.print("[Unknown command: %(input)]")
continue
}
System.write("\nAssistant: ")
Stdout.flush()
var result = chat.send(input)
if (result["error"] != null) {
System.print("[Error: %(result["error"])]")
} else {
System.print(result["content"])
if (result["usage"] != null) {
var usage = result["usage"]
System.print("\n[tokens: %(usage["prompt_tokens"]) prompt, %(usage["completion_tokens"]) completion]")
}
}
}