// OpenAI, or any server that speaks its API: a chat, a streamed answer, a tool call answered and
// sent back, embeddings, the Responses API, and the failures a program must expect.
//
//   OPENAI_API_KEY=... OPENAI_MODEL=... quillo run openai.qwe
//   then open http://localhost:8080/ask, /stream, /tools, /embed, /response and /failures
//
// OPENAI_BASE_URL points it elsewhere: http://127.0.0.1:11434/v1 for Ollama, or vLLM, LM Studio,
// LiteLLM. There is no default chat model, as those servers have their own names.

use "openai.qwer"

let weather = openai_tool("get_weather", "The weather in a city", {
    type: "object", properties: { city: { type: "string" } }, required: ["city"],
})?

route GET /ask = { answer: openai_ask("Name a prime number.", "Answer in one word.", {})? }

route GET /stream {
    let r = openai_chat_stream("Write a haiku", {})?
    { text: r.text, finish: r.finish_reason, tokens: r.usage.total_tokens }
}

route GET /tools {
    let messages = [{ role: "user", content: "Weather in Paris?" }]
    let first = openai_chat({ messages: messages, tools: [weather] }, {})?
    let results = map(first.tool_calls, (c) => openai_tool_result(c.id, { city: c.arguments.city, celsius: 18 }))
    let second = openai_chat({ messages: openai_continue(messages, first, results)?, tools: [weather] }, {})?
    { asked: first.finish_reason, city: first.tool_calls[0].arguments.city, answer: second.text }
}

// A tool call streamed comes in pieces.
route GET /tools-stream {
    let r = openai_chat_stream({ messages: "Weather in Paris?", tools: [weather] }, {})?
    { finish: r.finish_reason, name: r.tool_calls[0].name, city: r.tool_calls[0].arguments.city }
}

route GET /embed {
    let e = openai_embeddings(["first", "second"], { dimensions: 3 })?
    { count: len(e.vectors), first: e.vectors[0], second: e.vectors[1], tokens: e.usage.total_tokens }
}

route GET /response {
    let r = openai_response({ input: "Say hello", instructions: "Be brief." }, {})?
    let s = openai_response_stream("Say hello", {})?
    { status: r.status, text: r.text, streamed: s.text, tokens: s.usage.total_tokens }
}

route GET /response-tool {
    let r = openai_response({ input: "Weather in Paris?", tools: [{ type: "function", name: "get_weather", parameters: {} }] }, {})?
    let call = r.tool_calls[0]
    let done = openai_response({ previous_response_id: r.id, input: [openai_function_output(call.id, "18 C")] }, {})?
    { city: call.arguments.city, answer: done.text }
}

route GET /models = { models: openai_models({})? }

route GET /failures = {
    retried: openai_ask("slow down", "", {})?,
    unknown: openai_ask("Hi", "", { model: "no-such-model" }).error,
    quota: openai_ask("out of quota", "", {}).error,
    bad_key: openai_ask("Hi", "", { api_key: "wrong" }).error,
    failed: openai_response("fail please", {}).error,
    cut_off: openai_ask("too long", "", {}).error,
}
