1import * as OpenRouterSchema from "@effect/ai-openrouter/OpenRouterSchema"
2import { assert, describe, it } from "@effect/vitest"
3import { Schema } from "effect"
4
5const choiceAnswer = {
6 type: "choice",
7 choice: "billing",
8 probabilities: { billing: 0.84, technical: 0.159, sales: 0.001 },
9 confidence: 0.596
10}
11
12const scoreAnswer = {
13 type: "score",
14 score: 1.6,
15 legend: { "0": "Calm", "1": "Frustrated", "2": "Very angry" },
16 probabilities: { "0": 0.05, "1": 0.3, "2": 0.65 },
17 confidence: 0.78
18}
19
20const noulAnswer = { type: "noul", noul: 0.999 }
21
22describe("OpenRouterSchema", () => {
23 it("encodes a decisions request with every question type", () => {
24 const request = {
25 model: "openai/gpt-4o-mini",
26 state: { message: "My card was charged twice.", orderId: "A-104" },
27 questions: {
28 department: {
29 type: "choice",
30 instructions: "Which team should handle this",
31 criteria: { billing: "Payment issues", technical: "Bugs" }
32 },
33 frustration: {
34 type: "score",
35 instructions: "How frustrated the customer appears",
36 criteria: ["Calm", "Frustrated", "Very angry"]
37 },
38 urgent: {
39 type: "noul",
40 instructions: "The message conveys urgency",
41 criteria: { false: "No time pressure", true: "Needs action now" }
42 }
43 }
44 } as const
45
46 const decoded = Schema.decodeUnknownSync(OpenRouterSchema.DecisionsRequest)(request)
47 const encoded = Schema.encodeSync(OpenRouterSchema.DecisionsRequest)(decoded)
48
49 assert.deepStrictEqual(JSON.parse(JSON.stringify(encoded)), request)
50 })
51
52 it("accepts a request carrying routing and tracing options", () => {
53 const decoded = Schema.decodeUnknownSync(OpenRouterSchema.DecisionsRequest)({
54 model: "openai/gpt-4o-mini",
55 state: "hello",
56 questions: { urgent: { type: "noul", instructions: "Urgent" } },
57 provider: { order: ["openai"] },
58 session_id: "session-1",
59 user: "user-1"
60 })
61
62 assert.strictEqual(decoded.session_id, "session-1")
63 assert.strictEqual(decoded.user, "user-1")
64 })
65
66 it("accepts a noul question without criteria", () => {
67 const decoded = Schema.decodeUnknownSync(OpenRouterSchema.NoulQuestion)({
68 type: "noul",
69 instructions: "The message conveys urgency"
70 })
71
72 assert.strictEqual(decoded.type, "noul")
73 assert.isUndefined(decoded.criteria)
74 })
75
76 it.each([
77 { name: "string", state: "a plain string" },
78 { name: "object", state: { message: "hi", orderId: "A-1" } },
79 { name: "array", state: ["first", "second"] }
80 ])("accepts a $name state", ({ state }) => {
81 const decoded = Schema.decodeUnknownSync(OpenRouterSchema.DecisionsRequest)({
82 model: "openai/gpt-4o-mini",
83 state,
84 questions: { urgent: { type: "noul", instructions: "Urgent" } }
85 })
86
87 assert.deepStrictEqual(decoded.state, state)
88 })
89
90 it("decodes a response with choice, score and noul answers", () => {
91 const response = {
92 id: "dec_123",
93 model: "openai/gpt-4o-mini",
94 provider: "OpenAI",
95 answers: { department: choiceAnswer, frustration: scoreAnswer, urgent: noulAnswer },
96 usage: { input_tokens: 312, output_tokens: 48, cost: 0.00042 }
97 }
98
99 const decoded = Schema.decodeUnknownSync(OpenRouterSchema.DecisionsResponse)(response)
100
101 assert.deepStrictEqual(JSON.parse(JSON.stringify(decoded)), response)
102 })
103
104 it("decodes a response without id, provider or cost", () => {
105 const decoded = Schema.decodeUnknownSync(OpenRouterSchema.DecisionsResponse)({
106 model: "openai/gpt-4o-mini",
107 answers: { urgent: noulAnswer },
108 usage: { input_tokens: 10, output_tokens: 2 }
109 })
110
111 assert.isUndefined(decoded.id)
112 assert.isUndefined(decoded.provider)
113 assert.isUndefined(decoded.usage.cost)
114 })
115
116 it.each([
117 { name: "choice answer without probabilities", answer: { type: "choice", choice: "billing" } },
118 { name: "choice answer without confidence", answer: { type: "choice", choice: "billing", probabilities: {} } },
119 { name: "score answer without probabilities", answer: { type: "score", score: 1.6 } },
120 { name: "score answer without legend", answer: { type: "score", score: 1.6, probabilities: { "0": 1 } } }
121 ])("decodes a $name, since the field is optional upstream", ({ answer }) => {
122 const decoded = Schema.decodeUnknownSync(OpenRouterSchema.Answer)(answer)
123
124 assert.strictEqual(decoded.type, (answer as { type: string }).type)
125 })
126
127 it.each([
128 { name: "choice answer without choice", answer: { type: "choice", probabilities: { billing: 1 } } },
129 { name: "score answer without score", answer: { type: "score", probabilities: { "0": 1 } } },
130 { name: "noul answer without noul", answer: { type: "noul" } },
131 { name: "answer with an unknown type", answer: { type: "rank", rank: [] } }
132 ])("rejects a $name", ({ answer }) => {
133 assert.throws(() => Schema.decodeUnknownSync(OpenRouterSchema.Answer)(answer))
134 })
135
136 it("rejects a response without usage", () => {
137 assert.throws(() =>
138 Schema.decodeUnknownSync(OpenRouterSchema.DecisionsResponse)({
139 model: "openai/gpt-4o-mini",
140 answers: { urgent: noulAnswer }
141 })
142 )
143 })
144})