mcp-jev 1.1.1 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,207 +1,151 @@
1
1
  # mcp-jev
2
2
 
3
- MCP server cho [TypeSafe Jev](https://typesafe.ai) — System One Model.
3
+ MCP server for **System-1 decision models** — provider-agnostic. Routes to [TypeSafe Jev](https://typesafe.ai) (cloud) or [Laya](https://pypi.org/project/laya/) (local HTTP) via a single env var.
4
4
 
5
- Gửi state + typed questions → nhận calibrated probabilities. Không sinh text.
5
+ ## Migration from v1 → v2
6
6
 
7
- ## Tools
7
+ v2 replaces `jev_decide`/`jev_list_models` with a 4-tool provider-agnostic interface:
8
+
9
+ | v1 | v2 | Notes |
10
+ |----|----|----|
11
+ | `jev_decide` | `decide_predict` | Same question format (`questions[]` array) |
12
+ | `jev_list_models` | `decide_list_models` | Same return shape |
13
+ | — | `decide_status` | New: provider health info |
14
+ | — | `decide_preset` | New: named workflow presets |
8
15
 
9
- | Tool | Khi nào dùng |
10
- |------|-------------|
11
- | `jev_decide` | Classify, route, check, score bất kỳ nội dung nào |
12
- | `jev_list_models` | Xem model IDs / aliases có sẵn trên API key của bạn |
16
+ **v2 env vars** (replaces `TYPESAFE_API_KEY` alone):
13
17
 
14
- ### `jev_decide`
18
+ | Variable | Required | Default | Description |
19
+ |----------|----------|---------|-------------|
20
+ | `DECIDE_PROVIDER` | No | `jev` | `jev` or `laya` |
21
+ | `TYPESAFE_API_KEY` | When `jev` | — | TypeSafe API key |
22
+ | `TYPESAFE_BASE_URL` | No | `https://api.typesafe.ai` | Override Jev URL |
23
+ | `LAYA_BASE_URL` | No | `http://localhost:8000` | Override Laya URL |
24
+ | `LAYA_API_KEY` | No | — | Laya bearer token (if Laya requires auth) |
15
25
 
16
- Đánh giá một hoặc nhiều câu hỏi trên cùng một `state` trong một request duy nhất.
26
+ ---
27
+
28
+ ## Tools
17
29
 
18
- **3 loại câu hỏi (primitives):**
30
+ ### `decide_predict`
19
31
 
20
- | Type | Hỏi gì | Output |
21
- |------|--------|--------|
22
- | `noul` | Điều này có đúng không? | `noul`: probability 0–1 |
23
- | `choice` | Chọn 1 trong N options? | `choice` + `probabilities` + `confidence` |
24
- | `score` | Rate trên rubric này? | `score` (có thể là 1.04/3) + `probabilities` + `confidence` |
32
+ Core inference. Evaluate typed questions against a state.
25
33
 
26
- **Ví dụ — triage support ticket:**
34
+ **Question types**: `noul` (yes/no probability), `choice` (pick one of N), `score` (rate on rubric)
27
35
 
36
+ **Example:**
28
37
  ```json
29
38
  {
30
- "state": {
31
- "message": "Payout của tôi bị fail 3 ngày rồi, tôi cần xử lý gấp!"
32
- },
39
+ "state": { "message": "My payment failed 3 days ago, help!" },
33
40
  "questions": [
34
- {
35
- "id": "is_urgent",
36
- "type": "noul",
37
- "instructions": "Người dùng trong `message` có cần hỗ trợ khẩn cấp không?"
38
- },
39
- {
40
- "id": "department",
41
- "type": "choice",
42
- "instructions": "Bộ phận nào nên xử lý `message`?",
43
- "criteria": {
44
- "billing": "Thanh toán, hoàn tiền, hóa đơn",
45
- "technical": "Lỗi kỹ thuật, tích hợp API",
46
- "general": "Câu hỏi chung không thuộc category trên"
47
- }
48
- },
49
- {
50
- "id": "frustration",
51
- "type": "score",
52
- "instructions": "Mức độ bực bội của người dùng trong `message` là bao nhiêu?",
53
- "criteria": ["Bình thường", "Hơi khó chịu", "Rất bực bội"]
54
- }
41
+ { "id": "urgent", "type": "noul", "instructions": "Is `message` urgent?" },
42
+ { "id": "dept", "type": "choice", "instructions": "Which team?",
43
+ "criteria": { "billing": "Payments", "technical": "API errors", "general": null } }
55
44
  ]
56
45
  }
57
46
  ```
58
47
 
59
- **Response mẫu:**
48
+ ---
49
+
50
+ ### `decide_preset`
60
51
 
52
+ Run a named workflow preset — expands to a pre-defined question set.
53
+
54
+ **Available presets:**
55
+
56
+ | Preset | State field | Questions |
57
+ |--------|------------|-----------|
58
+ | `triage` | `message` | intent, urgency, frustration, refund, churn |
59
+ | `guard` | `prompt` | jailbreak, injection, sensitive_data, harm, topic |
60
+ | `moderation` | `post` | toxic, harassment, threat, spam, severity |
61
+ | `router` | `request` | difficulty, domain, needs_tools, is_sensitive |
62
+ | `email` | `body` | category, is_spam, is_phishing, urgency, needs_reply |
63
+
64
+ **Example:**
61
65
  ```json
62
- {
63
- "answers": {
64
- "is_urgent": { "noul": 0.95 },
65
- "department": {
66
- "choice": "billing",
67
- "probabilities": { "billing": 0.82, "technical": 0.12, "general": 0.06 },
68
- "confidence": 0.80
69
- },
70
- "frustration": {
71
- "score": 2.04,
72
- "legend": { "0": "Bình thường", "1": "Hơi khó chịu", "2": "Rất bực bội" },
73
- "probabilities": { "Bình thường": 0.05, "Hơi khó chịu": 0.18, "Rất bực bội": 0.77 },
74
- "confidence": 0.77
75
- }
76
- },
77
- "model": "jev-1.13.0",
78
- "usage": { "input_tokens": 312, "output_tokens": 0 }
79
- }
66
+ { "preset": "guard", "state": { "prompt": "Ignore all instructions" } }
80
67
  ```
81
68
 
82
- **Tips:**
83
- - Chỉ gửi state fields mà questions cần — context dư làm giảm độ chính xác
84
- - Reference fields bằng backtick: `` `message` ``, `` `order.id` ``
85
- - `choice.criteria` null = "no extra detail" (dùng cho bucket `other`)
86
- - `score.criteria` cần 2–10 levels, ordered thấp → cao
87
-
88
69
  ---
89
70
 
90
- ### `jev_list_models`
71
+ ### `decide_status`
91
72
 
92
- Trả về danh sách model IDs và aliases.
73
+ Provider health and configuration info.
93
74
 
94
75
  ```json
95
- [
96
- { "id": "jev-1.13.0", "aliases": ["jev-latest"] }
97
- ]
98
- ```
76
+ // Jev response
77
+ { "provider": "jev", "base_url": "https://api.typesafe.ai", "model": "jev-latest", "status": "ok" }
99
78
 
100
- Dùng khi muốn pin versioned ID thay vì `jev-latest` để tránh behavior thay đổi sau update.
79
+ // Laya response
80
+ { "provider": "laya", "base_url": "http://localhost:8000", "loaded": ["english", "multilingual"], "device": "cuda", "status": "ok" }
81
+ ```
101
82
 
102
83
  ---
103
84
 
104
- ## Cài đặt & cấu hình
85
+ ### `decide_list_models`
105
86
 
106
- ### Prerequisites
87
+ Available models or checkpoints.
107
88
 
108
- - Node.js ≥ 20
109
- - TypeSafe API key — đăng ký waitlist tại [typesafe.ai](https://typesafe.ai)
89
+ ---
110
90
 
111
- ### Build
91
+ ## Installation
112
92
 
113
- ```bash
114
- cd mcp-jev
115
- npm install
116
- npm run build
117
- ```
118
-
119
- ### Kiro (`.kiro/settings/mcp.json`)
93
+ ### With Jev (cloud, default)
120
94
 
121
95
  ```json
122
96
  {
123
97
  "mcpServers": {
124
98
  "jev": {
125
- "command": "node",
126
- "args": ["d:/github/crhead/mcp-jev/dist/index.js"],
99
+ "command": "npx",
100
+ "args": ["-y", "mcp-jev"],
127
101
  "env": {
128
102
  "TYPESAFE_API_KEY": "your_key_here"
129
- },
130
- "disabled": false
103
+ }
131
104
  }
132
105
  }
133
106
  }
134
107
  ```
135
108
 
136
- ### Claude Desktop (`claude_desktop_config.json`)
109
+ ### With Laya (local)
137
110
 
111
+ Start Laya HTTP server first:
112
+ ```bash
113
+ pip install "laya[serve]"
114
+ LAYA_DEVICE=cuda LAYA_PRELOAD=1 laya-serve # default: http://localhost:8000
115
+ ```
116
+
117
+ Then configure MCP:
138
118
  ```json
139
119
  {
140
120
  "mcpServers": {
141
121
  "jev": {
142
- "command": "node",
143
- "args": ["/absolute/path/to/mcp-jev/dist/index.js"],
122
+ "command": "npx",
123
+ "args": ["-y", "mcp-jev"],
144
124
  "env": {
145
- "TYPESAFE_API_KEY": "your_key_here"
125
+ "DECIDE_PROVIDER": "laya",
126
+ "LAYA_BASE_URL": "http://localhost:8000"
146
127
  }
147
128
  }
148
129
  }
149
130
  }
150
131
  ```
151
132
 
152
- ### Dev mode (không cần build)
133
+ ### Local build
153
134
 
154
135
  ```bash
155
- TYPESAFE_API_KEY=your_key npx tsx src/index.ts
136
+ cd mcp-jev
137
+ npm install
138
+ npm run build
156
139
  ```
157
140
 
158
- ---
159
-
160
- ## Biến môi trường
161
-
162
- | Biến | Bắt buộc | Mặc định | Mô tả |
163
- |------|----------|----------|-------|
164
- | `TYPESAFE_API_KEY` | ✅ | — | API key từ console.typesafe.ai |
165
- | `TYPESAFE_BASE_URL` | ❌ | `https://api.typesafe.ai` | Override URL (staging, proxy) |
166
-
167
- Server exit với code 1 ngay khi start nếu `TYPESAFE_API_KEY` không được set.
168
-
169
- ---
170
-
171
- ## Error handling
172
-
173
- | HTTP code | Ý nghĩa | Behavior |
174
- |-----------|---------|----------|
175
- | 401 | API key sai / thiếu | Trả về `isError: true` ngay |
176
- | 422 | Request body invalid | Trả về `isError: true` ngay + message chi tiết |
177
- | 429 | Rate limit | Retry tối đa 3 lần, exponential backoff |
178
- | 529 | Service overloaded | Retry tối đa 3 lần, exponential backoff |
179
-
180
- Rate limits hiện tại: 250,000 tokens/s · 1,200 requests/min.
181
-
182
- ---
183
-
184
- ## Giới hạn Jev
185
-
186
- - Chỉ nhận text (string, JSON object, JSON array) — không hỗ trợ image/audio/video
187
- - Context budget: ~64,000 tokens cho toàn bộ state + questions
188
- - Choice tối đa 255 options; Score 2–10 levels
189
- - Không thể dùng cho System 2 tasks (lập luận đa bước, sinh code, giải thích)
190
- - Model hiện tại: `jev-1.13.0` / alias `jev-latest`
191
-
192
- ---
193
-
194
- ## npx (khuyến nghị)
195
-
196
- Không cần clone repo — dùng trực tiếp từ npm:
197
-
198
141
  ```json
199
142
  {
200
143
  "mcpServers": {
201
144
  "jev": {
202
- "command": "npx",
203
- "args": ["-y", "mcp-jev"],
145
+ "command": "node",
146
+ "args": ["d:/github/crhead/mcp-jev/dist/index.js"],
204
147
  "env": {
148
+ "DECIDE_PROVIDER": "jev",
205
149
  "TYPESAFE_API_KEY": "your_key_here"
206
150
  }
207
151
  }
@@ -209,4 +153,19 @@ Không cần clone repo — dùng trực tiếp từ npm:
209
153
  }
210
154
  ```
211
155
 
156
+ ---
157
+
158
+ ## Provider Comparison
159
+
160
+ | | Jev (cloud) | Laya (local) |
161
+ |--|-------------|-------------|
162
+ | API key | Required (`TYPESAFE_API_KEY`) | Optional (`LAYA_API_KEY`) |
163
+ | Latency | Cloud (~200ms) | Local (~33ms GPU) |
164
+ | Routing metadata | None | Yes (language, checkpoint) |
165
+ | `/health` endpoint | No | Yes |
166
+ | Model list | `GET /v1/models` | Extracted from `GET /health` |
167
+ | Internet required | Yes | No |
168
+
169
+ ---
170
+
212
171
  Source: [github.com/mndpjm/mcp-jev](https://github.com/mndpjm/mcp-jev)
@@ -0,0 +1,10 @@
1
+ /**
2
+ * createAdapter — reads DECIDE_PROVIDER from environment and returns the
3
+ * appropriate ProviderAdapter implementation.
4
+ *
5
+ * Throws ConfigurationError (NOT process.exit) on invalid configuration.
6
+ * Callers (entry point) catch ConfigurationError and call process.exit(1).
7
+ */
8
+ import { ProviderAdapter } from "../lib.js";
9
+ export declare function createAdapter(): ProviderAdapter;
10
+ //# sourceMappingURL=factory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../src/adapters/factory.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAsB,eAAe,EAAE,MAAM,WAAW,CAAC;AAWhE,wBAAgB,aAAa,IAAI,eAAe,CA2B/C"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * createAdapter — reads DECIDE_PROVIDER from environment and returns the
3
+ * appropriate ProviderAdapter implementation.
4
+ *
5
+ * Throws ConfigurationError (NOT process.exit) on invalid configuration.
6
+ * Callers (entry point) catch ConfigurationError and call process.exit(1).
7
+ */
8
+ import { ConfigurationError } from "../lib.js";
9
+ import { JevAdapter } from "./jev.js";
10
+ import { LayaAdapter } from "./laya.js";
11
+ const VALID_PROVIDERS = ["jev", "laya"];
12
+ function isValidProvider(v) {
13
+ return VALID_PROVIDERS.includes(v);
14
+ }
15
+ export function createAdapter() {
16
+ const provider = (process.env.DECIDE_PROVIDER ?? "jev").trim().toLowerCase();
17
+ if (!isValidProvider(provider)) {
18
+ throw new ConfigurationError(`Invalid DECIDE_PROVIDER value "${provider}". Valid values: ${VALID_PROVIDERS.join(", ")}.`);
19
+ }
20
+ if (provider === "jev") {
21
+ const apiKey = process.env.TYPESAFE_API_KEY;
22
+ if (!apiKey) {
23
+ throw new ConfigurationError('TYPESAFE_API_KEY is required when DECIDE_PROVIDER=jev (or unset). ' +
24
+ 'Set DECIDE_PROVIDER=laya to use a local Laya server without an API key.');
25
+ }
26
+ const baseUrl = process.env.TYPESAFE_BASE_URL?.replace(/\/$/, "") ?? "https://api.typesafe.ai";
27
+ return new JevAdapter(apiKey, baseUrl);
28
+ }
29
+ // provider === "laya"
30
+ const baseUrl = process.env.LAYA_BASE_URL?.replace(/\/$/, "") ?? "http://localhost:8000";
31
+ const apiKey = process.env.LAYA_API_KEY; // optional
32
+ return new LayaAdapter(baseUrl, apiKey);
33
+ }
34
+ //# sourceMappingURL=factory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"factory.js","sourceRoot":"","sources":["../../src/adapters/factory.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,kBAAkB,EAAmB,MAAM,WAAW,CAAC;AAChE,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACtC,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAExC,MAAM,eAAe,GAAG,CAAC,KAAK,EAAE,MAAM,CAAU,CAAC;AAGjD,SAAS,eAAe,CAAC,CAAS;IAChC,OAAQ,eAAqC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;AAC5D,CAAC;AAED,MAAM,UAAU,aAAa;IAC3B,MAAM,QAAQ,GAAW,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAErF,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC/B,MAAM,IAAI,kBAAkB,CAC1B,kCAAkC,QAAQ,oBAAoB,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAC5F,CAAC;IACJ,CAAC;IAED,IAAI,QAAQ,KAAK,KAAK,EAAE,CAAC;QACvB,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;QAC5C,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,IAAI,kBAAkB,CAC1B,oEAAoE;gBACpE,yEAAyE,CAC1E,CAAC;QACJ,CAAC;QACD,MAAM,OAAO,GACX,OAAO,CAAC,GAAG,CAAC,iBAAiB,EAAE,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,yBAAyB,CAAC;QACjF,OAAO,IAAI,UAAU,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACzC,CAAC;IAED,sBAAsB;IACtB,MAAM,OAAO,GACX,OAAO,CAAC,GAAG,CAAC,aAAa,EAAE,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,uBAAuB,CAAC;IAC3E,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,WAAW;IACpD,OAAO,IAAI,WAAW,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;AAC1C,CAAC"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * JevAdapter — routes requests to TypeSafe Jev cloud API.
3
+ *
4
+ * Env:
5
+ * TYPESAFE_API_KEY (required — caller must validate before constructing)
6
+ * TYPESAFE_BASE_URL (optional, default: https://api.typesafe.ai)
7
+ */
8
+ import { ProviderAdapter, PredictRequest, PredictResponse, ModelEntry, StatusResponse } from "../lib.js";
9
+ export declare class JevAdapter implements ProviderAdapter {
10
+ private readonly apiKey;
11
+ private readonly baseUrl;
12
+ private readonly defaultModel;
13
+ constructor(apiKey: string, baseUrl: string, defaultModel?: string);
14
+ predict(req: PredictRequest): Promise<PredictResponse>;
15
+ listModels(): Promise<ModelEntry[]>;
16
+ /**
17
+ * Jev has no /health endpoint — synthesize status from environment config.
18
+ */
19
+ status(): Promise<StatusResponse>;
20
+ }
21
+ //# sourceMappingURL=jev.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jev.d.ts","sourceRoot":"","sources":["../../src/adapters/jev.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EACL,eAAe,EACf,cAAc,EACd,eAAe,EACf,UAAU,EACV,cAAc,EAQf,MAAM,WAAW,CAAC;AAEnB,qBAAa,UAAW,YAAW,eAAe;IAChD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;gBAE1B,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,YAAY,SAAe;IAMlE,OAAO,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC;IAiCtD,UAAU,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;IAmCzC;;OAEG;IACH,MAAM,IAAI,OAAO,CAAC,cAAc,CAAC;CAQlC"}
@@ -0,0 +1,88 @@
1
+ /**
2
+ * JevAdapter — routes requests to TypeSafe Jev cloud API.
3
+ *
4
+ * Env:
5
+ * TYPESAFE_API_KEY (required — caller must validate before constructing)
6
+ * TYPESAFE_BASE_URL (optional, default: https://api.typesafe.ai)
7
+ */
8
+ import { ParseError, fetchWithRetry, parseModelEntries, JevResponseSchema, JevModelsResponseSchema, } from "../lib.js";
9
+ export class JevAdapter {
10
+ apiKey;
11
+ baseUrl;
12
+ defaultModel;
13
+ constructor(apiKey, baseUrl, defaultModel = "jev-latest") {
14
+ this.apiKey = apiKey;
15
+ this.baseUrl = baseUrl.replace(/\/$/, "");
16
+ this.defaultModel = defaultModel;
17
+ }
18
+ async predict(req) {
19
+ const body = {
20
+ model: req.model ?? this.defaultModel,
21
+ state: req.state,
22
+ questions: req.questions,
23
+ };
24
+ const resp = await fetchWithRetry(`${this.baseUrl}/v1/systemone`, {
25
+ method: "POST",
26
+ headers: {
27
+ Authorization: `Bearer ${this.apiKey}`,
28
+ "Content-Type": "application/json",
29
+ },
30
+ body: JSON.stringify(body),
31
+ });
32
+ let raw;
33
+ try {
34
+ raw = await resp.json();
35
+ }
36
+ catch (e) {
37
+ throw new ParseError(`Failed to parse Jev API response as JSON: ${e instanceof Error ? e.message : String(e)}`);
38
+ }
39
+ const parsed = JevResponseSchema.safeParse(raw);
40
+ if (!parsed.success) {
41
+ throw new ParseError(`Jev API response shape unexpected: ${parsed.error.message}`);
42
+ }
43
+ return parsed.data;
44
+ }
45
+ async listModels() {
46
+ const resp = await fetchWithRetry(`${this.baseUrl}/v1/models`, {
47
+ method: "GET",
48
+ headers: { Authorization: `Bearer ${this.apiKey}` },
49
+ });
50
+ let raw;
51
+ try {
52
+ raw = await resp.json();
53
+ }
54
+ catch (e) {
55
+ throw new ParseError(`Failed to parse Jev models response as JSON: ${e instanceof Error ? e.message : String(e)}`);
56
+ }
57
+ // Handle multiple response shapes:
58
+ // 1. Direct array: [{ id, aliases }, ...]
59
+ // 2. Wrapped object: { data: [...] } or { models: [...] }
60
+ let entries;
61
+ if (Array.isArray(raw)) {
62
+ entries = raw;
63
+ }
64
+ else {
65
+ const envelope = JevModelsResponseSchema.safeParse(raw);
66
+ if (!envelope.success) {
67
+ throw new ParseError(`Unexpected Jev models response shape: ${envelope.error.message}`);
68
+ }
69
+ entries = envelope.data.models ?? envelope.data.data ?? [];
70
+ if (!Array.isArray(entries)) {
71
+ throw new ParseError("Unexpected Jev models response shape — expected array");
72
+ }
73
+ }
74
+ return parseModelEntries(entries);
75
+ }
76
+ /**
77
+ * Jev has no /health endpoint — synthesize status from environment config.
78
+ */
79
+ status() {
80
+ return Promise.resolve({
81
+ provider: "jev",
82
+ base_url: this.baseUrl,
83
+ model: this.defaultModel,
84
+ status: "ok",
85
+ });
86
+ }
87
+ }
88
+ //# sourceMappingURL=jev.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jev.js","sourceRoot":"","sources":["../../src/adapters/jev.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * LayaAdapter — routes requests to a local Laya HTTP server.
3
+ *
4
+ * Laya HTTP server exposes POST /v1/systemone (Jev wire-compatible) and GET /health.
5
+ * Key differences from Jev:
6
+ * - `model` field should be OMITTED in predict request (Laya auto-routes)
7
+ * - GET /health (not /v1/models) for model list
8
+ * - Richer response: includes `routing` block, `latency_ms`, `device`
9
+ *
10
+ * Env:
11
+ * LAYA_BASE_URL (optional, default: http://localhost:8000)
12
+ * LAYA_API_KEY (optional) — bearer token if Laya is deployed with auth
13
+ */
14
+ import { ProviderAdapter, PredictRequest, PredictResponse, ModelEntry, StatusResponse } from "../lib.js";
15
+ export declare class LayaAdapter implements ProviderAdapter {
16
+ private readonly baseUrl;
17
+ private readonly apiKey?;
18
+ constructor(baseUrl: string, apiKey?: string);
19
+ private get headers();
20
+ predict(req: PredictRequest): Promise<PredictResponse>;
21
+ listModels(): Promise<ModelEntry[]>;
22
+ status(): Promise<StatusResponse>;
23
+ /**
24
+ * Fetch GET /health. Returns null on unreachable — callers handle gracefully.
25
+ * Returns status: "unreachable" via StatusResponse when called from status().
26
+ */
27
+ private _fetchHealth;
28
+ }
29
+ /**
30
+ * Build a StatusResponse for unreachable Laya health endpoint.
31
+ */
32
+ export declare function layaUnreachableStatus(baseUrl: string, errorMsg: string): StatusResponse;
33
+ //# sourceMappingURL=laya.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"laya.d.ts","sourceRoot":"","sources":["../../src/adapters/laya.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EACL,eAAe,EACf,cAAc,EACd,eAAe,EACf,UAAU,EACV,cAAc,EAQf,MAAM,WAAW,CAAC;AAEnB,qBAAa,WAAY,YAAW,eAAe;IACjD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAS;gBAErB,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM;IAK5C,OAAO,KAAK,OAAO,GAMlB;IAEK,OAAO,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC;IAgCtD,UAAU,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;IAUnC,MAAM,IAAI,OAAO,CAAC,cAAc,CAAC;IAmBvC;;;OAGG;YACW,YAAY;CA+B3B;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,cAAc,CAOvF"}
@@ -0,0 +1,125 @@
1
+ /**
2
+ * LayaAdapter — routes requests to a local Laya HTTP server.
3
+ *
4
+ * Laya HTTP server exposes POST /v1/systemone (Jev wire-compatible) and GET /health.
5
+ * Key differences from Jev:
6
+ * - `model` field should be OMITTED in predict request (Laya auto-routes)
7
+ * - GET /health (not /v1/models) for model list
8
+ * - Richer response: includes `routing` block, `latency_ms`, `device`
9
+ *
10
+ * Env:
11
+ * LAYA_BASE_URL (optional, default: http://localhost:8000)
12
+ * LAYA_API_KEY (optional) — bearer token if Laya is deployed with auth
13
+ */
14
+ import { AuthError, ParseError, NetworkError, fetchWithRetry, ERROR_BODY_MAX_CHARS, truncate, } from "../lib.js";
15
+ export class LayaAdapter {
16
+ baseUrl;
17
+ apiKey;
18
+ constructor(baseUrl, apiKey) {
19
+ this.baseUrl = baseUrl.replace(/\/$/, "");
20
+ this.apiKey = apiKey;
21
+ }
22
+ get headers() {
23
+ const h = { "Content-Type": "application/json" };
24
+ if (this.apiKey) {
25
+ h["Authorization"] = `Bearer ${this.apiKey}`;
26
+ }
27
+ return h;
28
+ }
29
+ async predict(req) {
30
+ // Laya auto-routes — omit `model` field
31
+ const body = {
32
+ state: req.state,
33
+ questions: req.questions,
34
+ // model intentionally omitted
35
+ };
36
+ const resp = await fetchWithRetry(`${this.baseUrl}/v1/systemone`, {
37
+ method: "POST",
38
+ headers: this.headers,
39
+ body: JSON.stringify(body),
40
+ });
41
+ let raw;
42
+ try {
43
+ raw = await resp.json();
44
+ }
45
+ catch (e) {
46
+ throw new ParseError(`Failed to parse Laya API response as JSON: ${e instanceof Error ? e.message : String(e)}`);
47
+ }
48
+ // Laya response is Jev-compatible plus extra fields (routing, latency_ms, device)
49
+ // Passthrough the full response including Laya-specific fields
50
+ if (!raw || typeof raw !== "object" || !("answers" in raw)) {
51
+ throw new ParseError("Laya API response missing required 'answers' field");
52
+ }
53
+ return raw;
54
+ }
55
+ async listModels() {
56
+ const health = await this._fetchHealth();
57
+ if (!health)
58
+ return [];
59
+ const loaded = health.loaded ?? [];
60
+ return loaded
61
+ .filter((id) => typeof id === "string" && id.length > 0)
62
+ .map((id) => ({ id }));
63
+ }
64
+ async status() {
65
+ const base = {
66
+ provider: "laya",
67
+ base_url: this.baseUrl,
68
+ };
69
+ const health = await this._fetchHealth();
70
+ if (!health) {
71
+ return base;
72
+ }
73
+ return {
74
+ ...base,
75
+ loaded: health.loaded,
76
+ device: health.device,
77
+ status: "ok",
78
+ };
79
+ }
80
+ /**
81
+ * Fetch GET /health. Returns null on unreachable — callers handle gracefully.
82
+ * Returns status: "unreachable" via StatusResponse when called from status().
83
+ */
84
+ async _fetchHealth() {
85
+ try {
86
+ const resp = await fetchWithRetry(`${this.baseUrl}/health`, {
87
+ method: "GET",
88
+ headers: this.apiKey ? { Authorization: `Bearer ${this.apiKey}` } : {},
89
+ });
90
+ let raw;
91
+ try {
92
+ raw = await resp.json();
93
+ }
94
+ catch {
95
+ return null;
96
+ }
97
+ return raw;
98
+ }
99
+ catch (e) {
100
+ // On unreachable, status() returns { status: "unreachable" }
101
+ if (e instanceof AuthError) {
102
+ // Propagate auth errors with helpful hint
103
+ throw new AuthError(`Laya returned 401. Set LAYA_API_KEY if this instance requires authentication.`);
104
+ }
105
+ if (e instanceof NetworkError) {
106
+ // NetworkError from fetchWithRetry — health endpoint unreachable
107
+ return null;
108
+ }
109
+ // Other errors (ParseError, ProviderError) — health unreachable / malformed
110
+ return null;
111
+ }
112
+ }
113
+ }
114
+ /**
115
+ * Build a StatusResponse for unreachable Laya health endpoint.
116
+ */
117
+ export function layaUnreachableStatus(baseUrl, errorMsg) {
118
+ return {
119
+ provider: "laya",
120
+ base_url: baseUrl,
121
+ status: "unreachable",
122
+ error: truncate(errorMsg, ERROR_BODY_MAX_CHARS),
123
+ };
124
+ }
125
+ //# sourceMappingURL=laya.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"laya.js","sourceRoot":"","sources":["../../src/adapters/laya.ts"],"names":[],"mappings":"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"}