promptimizer 0.1.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 +63 -0
- package/dist/classify.d.ts +4 -0
- package/dist/client.d.ts +54 -0
- package/dist/index.cjs +315 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +279 -0
- package/dist/providers.cjs +74 -0
- package/dist/providers.d.ts +25 -0
- package/dist/providers.js +46 -0
- package/dist/types.d.ts +123 -0
- package/package.json +74 -0
package/README.md
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# promptimizer
|
|
2
|
+
|
|
3
|
+
OpenAI-compatible TypeScript SDK for [Promptimizer](https://hackathon-omega-liart.vercel.app). Route each request to the cheapest adequate model, cache repeated prefixes, and keep a quality gate so savings do not silently degrade hard answers.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npm install promptimizer
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Account + BYOK
|
|
10
|
+
|
|
11
|
+
Create a `pmz_live_` key at `/account`, connect a provider in the console or CLI, then:
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { Promptimizer } from "promptimizer";
|
|
15
|
+
|
|
16
|
+
const client = new Promptimizer({
|
|
17
|
+
apiKey: process.env.PROMPTIMIZER_API_KEY,
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
const completion = await client.chat.completions.create({
|
|
21
|
+
messages: [{ role: "user", content: "What is 17 * 24?" }],
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
console.log(completion.choices[0].message.content);
|
|
25
|
+
console.log(completion.promptimizer);
|
|
26
|
+
console.log(completion.usage.cost);
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
The default gateway is the hosted app. Override with `gatewayURL` or `PROMPTIMIZER_URL`.
|
|
30
|
+
|
|
31
|
+
Connect a provider from code if it is not already saved on the account:
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
await client.connect({
|
|
35
|
+
provider: "baseten",
|
|
36
|
+
apiKey: process.env.BASETEN_API_KEY,
|
|
37
|
+
});
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Drop-in with the official OpenAI SDK
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
import OpenAI from "openai";
|
|
44
|
+
|
|
45
|
+
const openai = new OpenAI({
|
|
46
|
+
apiKey: process.env.PROMPTIMIZER_API_KEY,
|
|
47
|
+
baseURL: "https://hackathon-omega-liart.vercel.app/api/v1",
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
await openai.chat.completions.create({
|
|
51
|
+
model: "auto",
|
|
52
|
+
messages: [{ role: "user", content: "Explain REST in two sentences." }],
|
|
53
|
+
});
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Local classification (no network)
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
import { classifyText } from "promptimizer";
|
|
60
|
+
|
|
61
|
+
classifyText("Design a rate limiter for 1 million QPS");
|
|
62
|
+
// recommended_tier: "frontier"
|
|
63
|
+
```
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ChatMessage, Classification, Tier } from "./types";
|
|
2
|
+
export declare function classifyMessages(messages: ChatMessage[]): Classification;
|
|
3
|
+
export declare function classifyText(text: string): Classification;
|
|
4
|
+
export declare function difficultyTier(complexity: number): Tier;
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { ChatCompletion, ChatCompletionRequest, ConnectOptions, PromptimizerOptions, SavingsSummary, Session } from "./types";
|
|
2
|
+
export declare class PromptimizerError extends Error {
|
|
3
|
+
readonly status: number;
|
|
4
|
+
readonly body?: unknown | undefined;
|
|
5
|
+
constructor(message: string, status: number, body?: unknown | undefined);
|
|
6
|
+
}
|
|
7
|
+
export declare const DEFAULT_GATEWAY: string;
|
|
8
|
+
export declare class Promptimizer {
|
|
9
|
+
readonly gatewayURL: string;
|
|
10
|
+
sessionId?: string;
|
|
11
|
+
apiKey?: string;
|
|
12
|
+
private readonly fetcher;
|
|
13
|
+
constructor(options?: PromptimizerOptions);
|
|
14
|
+
static connect(options: ConnectOptions & {
|
|
15
|
+
gatewayURL?: string;
|
|
16
|
+
}): Promise<{
|
|
17
|
+
client: Promptimizer;
|
|
18
|
+
session: Session;
|
|
19
|
+
}>;
|
|
20
|
+
connect(options: ConnectOptions): Promise<Session>;
|
|
21
|
+
providers(): Promise<{
|
|
22
|
+
object: string;
|
|
23
|
+
data: Array<{
|
|
24
|
+
id: string;
|
|
25
|
+
label: string;
|
|
26
|
+
base_url: string;
|
|
27
|
+
env: string;
|
|
28
|
+
}>;
|
|
29
|
+
}>;
|
|
30
|
+
savings(): Promise<SavingsSummary>;
|
|
31
|
+
session(): Promise<Session>;
|
|
32
|
+
models(): Promise<{
|
|
33
|
+
object: string;
|
|
34
|
+
data: Session["models"];
|
|
35
|
+
baseline_model: string | null;
|
|
36
|
+
}>;
|
|
37
|
+
updateFleet(body: {
|
|
38
|
+
overrides?: Record<string, string>;
|
|
39
|
+
selected?: Record<string, boolean>;
|
|
40
|
+
baseline_model?: string;
|
|
41
|
+
}): Promise<Session>;
|
|
42
|
+
classify(input: {
|
|
43
|
+
messages?: ChatCompletionRequest["messages"];
|
|
44
|
+
prompt?: string;
|
|
45
|
+
}): Promise<unknown>;
|
|
46
|
+
benchmark(compareAlwaysFrontier?: boolean): Promise<unknown>;
|
|
47
|
+
readonly chat: {
|
|
48
|
+
completions: {
|
|
49
|
+
create: (request: ChatCompletionRequest) => Promise<ChatCompletion>;
|
|
50
|
+
};
|
|
51
|
+
};
|
|
52
|
+
createChatCompletion(request: ChatCompletionRequest): Promise<ChatCompletion>;
|
|
53
|
+
private request;
|
|
54
|
+
}
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
DEFAULT_GATEWAY: () => DEFAULT_GATEWAY,
|
|
24
|
+
PROVIDERS: () => PROVIDERS,
|
|
25
|
+
Promptimizer: () => Promptimizer,
|
|
26
|
+
PromptimizerError: () => PromptimizerError,
|
|
27
|
+
classifyMessages: () => classifyMessages,
|
|
28
|
+
classifyText: () => classifyText,
|
|
29
|
+
difficultyTier: () => difficultyTier,
|
|
30
|
+
findProvider: () => findProvider,
|
|
31
|
+
publicCatalog: () => publicCatalog,
|
|
32
|
+
resolveBaseURL: () => resolveBaseURL
|
|
33
|
+
});
|
|
34
|
+
module.exports = __toCommonJS(index_exports);
|
|
35
|
+
|
|
36
|
+
// src/client.ts
|
|
37
|
+
var PromptimizerError = class extends Error {
|
|
38
|
+
constructor(message, status, body) {
|
|
39
|
+
super(message);
|
|
40
|
+
this.status = status;
|
|
41
|
+
this.body = body;
|
|
42
|
+
this.name = "PromptimizerError";
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
var DEFAULT_GATEWAY = (process.env.PROMPTIMIZER_URL || "https://hackathon-omega-liart.vercel.app/api").replace(/\/$/, "");
|
|
46
|
+
var Promptimizer = class _Promptimizer {
|
|
47
|
+
gatewayURL;
|
|
48
|
+
sessionId;
|
|
49
|
+
apiKey;
|
|
50
|
+
fetcher;
|
|
51
|
+
constructor(options = {}) {
|
|
52
|
+
this.gatewayURL = (options.gatewayURL ?? options.baseURL ?? DEFAULT_GATEWAY).replace(/\/$/, "");
|
|
53
|
+
this.sessionId = options.sessionId;
|
|
54
|
+
this.apiKey = options.apiKey;
|
|
55
|
+
this.fetcher = options.fetch ?? fetch;
|
|
56
|
+
}
|
|
57
|
+
static async connect(options) {
|
|
58
|
+
const client = new _Promptimizer({
|
|
59
|
+
gatewayURL: options.gatewayURL,
|
|
60
|
+
apiKey: options.accountKey
|
|
61
|
+
});
|
|
62
|
+
const session = await client.connect(options);
|
|
63
|
+
return { client, session };
|
|
64
|
+
}
|
|
65
|
+
async connect(options) {
|
|
66
|
+
const session = await this.request("/v1/providers/connect", {
|
|
67
|
+
method: "POST",
|
|
68
|
+
body: JSON.stringify({
|
|
69
|
+
mode: options.mode ?? "byok",
|
|
70
|
+
label: options.label,
|
|
71
|
+
provider: options.provider,
|
|
72
|
+
base_url: options.baseURL,
|
|
73
|
+
api_key: options.apiKey
|
|
74
|
+
})
|
|
75
|
+
});
|
|
76
|
+
this.sessionId = session.session_id;
|
|
77
|
+
return session;
|
|
78
|
+
}
|
|
79
|
+
async providers() {
|
|
80
|
+
return this.request(
|
|
81
|
+
"/v1/providers"
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
async savings() {
|
|
85
|
+
return this.request("/v1/savings");
|
|
86
|
+
}
|
|
87
|
+
async session() {
|
|
88
|
+
return this.request("/v1/session");
|
|
89
|
+
}
|
|
90
|
+
async models() {
|
|
91
|
+
return this.request(
|
|
92
|
+
"/v1/models"
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
async updateFleet(body) {
|
|
96
|
+
return this.request("/v1/models", { method: "PATCH", body: JSON.stringify(body) });
|
|
97
|
+
}
|
|
98
|
+
async classify(input) {
|
|
99
|
+
return this.request("/v1/classify", { method: "POST", body: JSON.stringify(input) });
|
|
100
|
+
}
|
|
101
|
+
async benchmark(compareAlwaysFrontier = true) {
|
|
102
|
+
return this.request("/v1/benchmark/run", {
|
|
103
|
+
method: "POST",
|
|
104
|
+
body: JSON.stringify({ compare_always_frontier: compareAlwaysFrontier })
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
chat = {
|
|
108
|
+
completions: {
|
|
109
|
+
create: (request) => this.createChatCompletion(request)
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
async createChatCompletion(request) {
|
|
113
|
+
return this.request("/v1/chat/completions", {
|
|
114
|
+
method: "POST",
|
|
115
|
+
body: JSON.stringify(request)
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
async request(path, init = {}) {
|
|
119
|
+
const headers = new Headers(init.headers);
|
|
120
|
+
headers.set("Content-Type", "application/json");
|
|
121
|
+
if (this.apiKey) {
|
|
122
|
+
headers.set("Authorization", `Bearer ${this.apiKey}`);
|
|
123
|
+
} else if (this.sessionId) {
|
|
124
|
+
headers.set("X-Promptimizer-Session", this.sessionId);
|
|
125
|
+
headers.set("Authorization", `Bearer ${this.sessionId}`);
|
|
126
|
+
}
|
|
127
|
+
const response = await this.fetcher(`${this.gatewayURL}${path}`, { ...init, headers });
|
|
128
|
+
const data = await response.json().catch(() => ({}));
|
|
129
|
+
if (!response.ok) {
|
|
130
|
+
const detail = typeof data === "object" && data && "detail" in data ? String(data.detail) : response.statusText;
|
|
131
|
+
throw new PromptimizerError(detail, response.status, data);
|
|
132
|
+
}
|
|
133
|
+
return data;
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
// src/classify.ts
|
|
138
|
+
var HIGH_RISK = /* @__PURE__ */ new Set(["system_design", "safety_sensitive", "code_debug", "reasoning"]);
|
|
139
|
+
function textFrom(messages) {
|
|
140
|
+
return messages.map((m) => {
|
|
141
|
+
if (typeof m.content === "string") return m.content;
|
|
142
|
+
return m.content.map((b) => b.text ?? "").join("\n");
|
|
143
|
+
}).join("\n").trim();
|
|
144
|
+
}
|
|
145
|
+
function classifyMessages(messages) {
|
|
146
|
+
return classifyText(textFrom(messages));
|
|
147
|
+
}
|
|
148
|
+
function classifyText(text) {
|
|
149
|
+
const words = text.split(/\s+/).filter(Boolean).length;
|
|
150
|
+
const lines = text.split("\n").length;
|
|
151
|
+
const features = {
|
|
152
|
+
code_fence: /```/.test(text),
|
|
153
|
+
code_kw: /\b(def |class |function |import |fn |pub |async |SELECT |goroutine|mutex|traceback)\b/i.test(
|
|
154
|
+
text
|
|
155
|
+
),
|
|
156
|
+
math: /(\$\$|\\frac|prove that|expected value|O\([nN]\)|\d+\s*[\*\^]\s*\d+)/i.test(text),
|
|
157
|
+
design: /\b(design|architect|rate limiter|distributed|consistency|shard|1 million QPS)\b/i.test(
|
|
158
|
+
text
|
|
159
|
+
),
|
|
160
|
+
reason: /\b(prove|why does|walk through|step by step|derive|contradiction|p-value)\b/i.test(
|
|
161
|
+
text
|
|
162
|
+
),
|
|
163
|
+
debug: /\b(bug|race|panic|fails on|diagnose|deadlock)\b/i.test(text),
|
|
164
|
+
summarize: /\b(summarize|tl;dr|in two sentences|eli5)\b/i.test(text),
|
|
165
|
+
translate: /\b(translate|traduce)\b/i.test(text),
|
|
166
|
+
creative: /\b(write a (poem|story|song)|haiku)\b/i.test(text),
|
|
167
|
+
safety: /\b(refund|legal|medical|hipaa|lawsuit|diagnosis)\b/i.test(text),
|
|
168
|
+
analysis: /\b(compare|trade-?off|versus|analyse|analyze|evaluate|should we)\b/i.test(text),
|
|
169
|
+
constraints: (text.match(/\b(must|include|constraints?|requirements?)\b/gi) ?? []).length,
|
|
170
|
+
words,
|
|
171
|
+
lines,
|
|
172
|
+
question_marks: (text.match(/\?/g) ?? []).length
|
|
173
|
+
};
|
|
174
|
+
const category = categoryOf(features);
|
|
175
|
+
const complexity = complexityOf(features, category);
|
|
176
|
+
const p_small_quality = pSmallQuality(features, category, complexity);
|
|
177
|
+
const quality_risk = riskOf(category, complexity, p_small_quality);
|
|
178
|
+
const recommended_tier = tierFromP(p_small_quality);
|
|
179
|
+
const signals = [
|
|
180
|
+
features.code_fence,
|
|
181
|
+
features.code_kw,
|
|
182
|
+
features.math,
|
|
183
|
+
features.design,
|
|
184
|
+
features.reason,
|
|
185
|
+
features.debug,
|
|
186
|
+
features.safety
|
|
187
|
+
].filter(Boolean).length;
|
|
188
|
+
const confidence = category === "factual_recall" && words < 16 ? 0.9 : Math.min(0.95, 0.55 + 0.12 * signals);
|
|
189
|
+
return {
|
|
190
|
+
complexity,
|
|
191
|
+
category,
|
|
192
|
+
confidence: Number(confidence.toFixed(3)),
|
|
193
|
+
recommended_tier,
|
|
194
|
+
quality_risk,
|
|
195
|
+
p_small_quality,
|
|
196
|
+
uncertainty: Number((1 - p_small_quality).toFixed(3)),
|
|
197
|
+
structured_output: Boolean(features.code_fence || features.constraints >= 1),
|
|
198
|
+
context_tokens_est: Math.max(1, Math.round(text.length / 4)),
|
|
199
|
+
rationale: `${category.replaceAll("_", " ")} L${complexity}. P(quality|small)=${p_small_quality}. Route to ${recommended_tier}.`,
|
|
200
|
+
features
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
function categoryOf(h) {
|
|
204
|
+
if (h.safety) return "safety_sensitive";
|
|
205
|
+
if (h.design) return "system_design";
|
|
206
|
+
if (h.debug && (h.code_fence || h.code_kw)) return "code_debug";
|
|
207
|
+
if (h.code_fence || h.code_kw) return "code_generation";
|
|
208
|
+
if (h.math && h.reason) return "reasoning";
|
|
209
|
+
if (h.math) return "math";
|
|
210
|
+
if (h.reason) return "reasoning";
|
|
211
|
+
if (h.translate) return "translation";
|
|
212
|
+
if (h.summarize) return "summarization";
|
|
213
|
+
if (h.creative) return "creative";
|
|
214
|
+
if (h.analysis) return "analysis";
|
|
215
|
+
if (h.words < 24 && h.question_marks >= 1) return "factual_recall";
|
|
216
|
+
return h.words > 80 ? "analysis" : "factual_recall";
|
|
217
|
+
}
|
|
218
|
+
function complexityOf(h, category) {
|
|
219
|
+
let score = 1;
|
|
220
|
+
if (h.words > 40) score += 1;
|
|
221
|
+
if (h.words > 120) score += 1;
|
|
222
|
+
if (h.lines > 12 || h.code_fence) score += 1;
|
|
223
|
+
if (h.constraints >= 2) score += 1;
|
|
224
|
+
if (h.design || h.reason) score += 1;
|
|
225
|
+
if (h.debug) score += 1;
|
|
226
|
+
if (["system_design", "reasoning", "safety_sensitive"].includes(category)) score = Math.max(score + 1, 4);
|
|
227
|
+
if (category === "code_generation") score = Math.max(score, 3);
|
|
228
|
+
if (category === "code_debug") score = Math.max(score, 4);
|
|
229
|
+
if (category === "factual_recall" && h.words < 20) score = Math.min(score, 2);
|
|
230
|
+
return Math.max(1, Math.min(5, score));
|
|
231
|
+
}
|
|
232
|
+
function pSmallQuality(h, category, complexity) {
|
|
233
|
+
let p = 0.96;
|
|
234
|
+
if (h.design || category === "system_design") p -= 0.28;
|
|
235
|
+
if (h.safety || category === "safety_sensitive") p -= 0.3;
|
|
236
|
+
if (h.debug || category === "code_debug") p -= 0.22;
|
|
237
|
+
if (h.reason || category === "reasoning") p -= 0.18;
|
|
238
|
+
if (complexity >= 5) p -= 0.22;
|
|
239
|
+
else if (complexity >= 4) p -= 0.14;
|
|
240
|
+
else if (complexity === 3) p -= 0.06;
|
|
241
|
+
if (h.words > 120) p -= 0.07;
|
|
242
|
+
if (h.constraints >= 2) p -= 0.07;
|
|
243
|
+
if (category === "code_generation") p -= 0.05;
|
|
244
|
+
if (category === "factual_recall" && h.words < 24) p = Math.max(p, 0.94);
|
|
245
|
+
return Number(Math.min(0.99, Math.max(0.05, p)).toFixed(3));
|
|
246
|
+
}
|
|
247
|
+
function riskOf(category, complexity, p) {
|
|
248
|
+
if (HIGH_RISK.has(category) || complexity >= 5 || p < 0.72) return "high";
|
|
249
|
+
if (complexity >= 3 || p < 0.9) return "medium";
|
|
250
|
+
return "low";
|
|
251
|
+
}
|
|
252
|
+
function tierFromP(p) {
|
|
253
|
+
if (p >= 0.9) return "economy";
|
|
254
|
+
if (p >= 0.72) return "standard";
|
|
255
|
+
return "frontier";
|
|
256
|
+
}
|
|
257
|
+
function difficultyTier(complexity) {
|
|
258
|
+
if (complexity <= 2) return "economy";
|
|
259
|
+
if (complexity === 3) return "standard";
|
|
260
|
+
return "frontier";
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// src/providers.ts
|
|
264
|
+
var PROVIDERS = [
|
|
265
|
+
{ id: "openai", label: "OpenAI", baseURL: "https://api.openai.com/v1", env: "OPENAI_API_KEY", hint: "sk-..." },
|
|
266
|
+
{ id: "groq", label: "Groq", baseURL: "https://api.groq.com/openai/v1", env: "GROQ_API_KEY", hint: "gsk_..." },
|
|
267
|
+
{ id: "baseten", label: "Baseten", baseURL: "https://inference.baseten.co/v1", env: "BASETEN_API_KEY", hint: "baseten key" },
|
|
268
|
+
{ id: "openrouter", label: "OpenRouter", baseURL: "https://openrouter.ai/api/v1", env: "OPENROUTER_API_KEY", hint: "sk-or-..." },
|
|
269
|
+
{ id: "together", label: "Together", baseURL: "https://api.together.xyz/v1", env: "TOGETHER_API_KEY", hint: "together key" },
|
|
270
|
+
{ id: "fireworks", label: "Fireworks", baseURL: "https://api.fireworks.ai/inference/v1", env: "FIREWORKS_API_KEY", hint: "fw_..." },
|
|
271
|
+
{ id: "deepseek", label: "DeepSeek", baseURL: "https://api.deepseek.com/v1", env: "DEEPSEEK_API_KEY", hint: "sk-..." },
|
|
272
|
+
{ id: "mistral", label: "Mistral", baseURL: "https://api.mistral.ai/v1", env: "MISTRAL_API_KEY", hint: "mistral key" },
|
|
273
|
+
{ id: "cerebras", label: "Cerebras", baseURL: "https://api.cerebras.ai/v1", env: "CEREBRAS_API_KEY", hint: "csk-..." },
|
|
274
|
+
{ id: "xai", label: "xAI", baseURL: "https://api.x.ai/v1", env: "XAI_API_KEY", hint: "xai-..." },
|
|
275
|
+
{ id: "google", label: "Google", baseURL: "https://generativelanguage.googleapis.com/v1beta/openai", env: "GOOGLE_API_KEY", hint: "AIza..." },
|
|
276
|
+
{ id: "perplexity", label: "Perplexity", baseURL: "https://api.perplexity.ai", env: "PERPLEXITY_API_KEY", hint: "pplx-..." },
|
|
277
|
+
{ id: "nvidia", label: "NVIDIA NIM", baseURL: "https://integrate.api.nvidia.com/v1", env: "NVIDIA_API_KEY", hint: "nvapi-..." },
|
|
278
|
+
{ id: "sambanova", label: "SambaNova", baseURL: "https://api.sambanova.ai/v1", env: "SAMBANOVA_API_KEY", hint: "samba key" },
|
|
279
|
+
{ id: "hyperbolic", label: "Hyperbolic", baseURL: "https://api.hyperbolic.xyz/v1", env: "HYPERBOLIC_API_KEY", hint: "hyperbolic key" },
|
|
280
|
+
{ id: "moonshot", label: "Moonshot", baseURL: "https://api.moonshot.ai/v1", env: "MOONSHOT_API_KEY", hint: "sk-..." },
|
|
281
|
+
{ id: "ollama", label: "Ollama", baseURL: "http://localhost:11434/v1", env: "OLLAMA_API_KEY", hint: "optional" }
|
|
282
|
+
];
|
|
283
|
+
function findProvider(input) {
|
|
284
|
+
const needle = input.trim().toLowerCase();
|
|
285
|
+
return PROVIDERS.find((p) => p.id === needle || p.label.toLowerCase() === needle) ?? null;
|
|
286
|
+
}
|
|
287
|
+
function publicCatalog() {
|
|
288
|
+
return PROVIDERS.map(({ id, label, baseURL, env }) => ({
|
|
289
|
+
id,
|
|
290
|
+
label,
|
|
291
|
+
base_url: baseURL,
|
|
292
|
+
env
|
|
293
|
+
}));
|
|
294
|
+
}
|
|
295
|
+
function resolveBaseURL(input) {
|
|
296
|
+
if (input.baseURL?.trim()) return { baseURL: input.baseURL.trim().replace(/\/$/, ""), provider: findProvider(input.provider ?? "") };
|
|
297
|
+
if (input.provider) {
|
|
298
|
+
const provider = findProvider(input.provider);
|
|
299
|
+
if (provider) return { baseURL: provider.baseURL, provider };
|
|
300
|
+
}
|
|
301
|
+
return { baseURL: null, provider: null };
|
|
302
|
+
}
|
|
303
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
304
|
+
0 && (module.exports = {
|
|
305
|
+
DEFAULT_GATEWAY,
|
|
306
|
+
PROVIDERS,
|
|
307
|
+
Promptimizer,
|
|
308
|
+
PromptimizerError,
|
|
309
|
+
classifyMessages,
|
|
310
|
+
classifyText,
|
|
311
|
+
difficultyTier,
|
|
312
|
+
findProvider,
|
|
313
|
+
publicCatalog,
|
|
314
|
+
resolveBaseURL
|
|
315
|
+
});
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { DEFAULT_GATEWAY, Promptimizer, PromptimizerError } from "./client";
|
|
2
|
+
export { classifyMessages, classifyText, difficultyTier } from "./classify";
|
|
3
|
+
export { PROVIDERS, findProvider, publicCatalog, resolveBaseURL } from "./providers";
|
|
4
|
+
export type { ProviderPreset } from "./providers";
|
|
5
|
+
export type { ChatCompletion, ChatCompletionRequest, ChatMessage, Classification, ConnectOptions, CostBreakdown, ModelInfo, PromptimizerOptions, SavingsSummary, Session, Tier, } from "./types.js";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
// src/client.ts
|
|
2
|
+
var PromptimizerError = class extends Error {
|
|
3
|
+
constructor(message, status, body) {
|
|
4
|
+
super(message);
|
|
5
|
+
this.status = status;
|
|
6
|
+
this.body = body;
|
|
7
|
+
this.name = "PromptimizerError";
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
var DEFAULT_GATEWAY = (process.env.PROMPTIMIZER_URL || "https://hackathon-omega-liart.vercel.app/api").replace(/\/$/, "");
|
|
11
|
+
var Promptimizer = class _Promptimizer {
|
|
12
|
+
gatewayURL;
|
|
13
|
+
sessionId;
|
|
14
|
+
apiKey;
|
|
15
|
+
fetcher;
|
|
16
|
+
constructor(options = {}) {
|
|
17
|
+
this.gatewayURL = (options.gatewayURL ?? options.baseURL ?? DEFAULT_GATEWAY).replace(/\/$/, "");
|
|
18
|
+
this.sessionId = options.sessionId;
|
|
19
|
+
this.apiKey = options.apiKey;
|
|
20
|
+
this.fetcher = options.fetch ?? fetch;
|
|
21
|
+
}
|
|
22
|
+
static async connect(options) {
|
|
23
|
+
const client = new _Promptimizer({
|
|
24
|
+
gatewayURL: options.gatewayURL,
|
|
25
|
+
apiKey: options.accountKey
|
|
26
|
+
});
|
|
27
|
+
const session = await client.connect(options);
|
|
28
|
+
return { client, session };
|
|
29
|
+
}
|
|
30
|
+
async connect(options) {
|
|
31
|
+
const session = await this.request("/v1/providers/connect", {
|
|
32
|
+
method: "POST",
|
|
33
|
+
body: JSON.stringify({
|
|
34
|
+
mode: options.mode ?? "byok",
|
|
35
|
+
label: options.label,
|
|
36
|
+
provider: options.provider,
|
|
37
|
+
base_url: options.baseURL,
|
|
38
|
+
api_key: options.apiKey
|
|
39
|
+
})
|
|
40
|
+
});
|
|
41
|
+
this.sessionId = session.session_id;
|
|
42
|
+
return session;
|
|
43
|
+
}
|
|
44
|
+
async providers() {
|
|
45
|
+
return this.request(
|
|
46
|
+
"/v1/providers"
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
async savings() {
|
|
50
|
+
return this.request("/v1/savings");
|
|
51
|
+
}
|
|
52
|
+
async session() {
|
|
53
|
+
return this.request("/v1/session");
|
|
54
|
+
}
|
|
55
|
+
async models() {
|
|
56
|
+
return this.request(
|
|
57
|
+
"/v1/models"
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
async updateFleet(body) {
|
|
61
|
+
return this.request("/v1/models", { method: "PATCH", body: JSON.stringify(body) });
|
|
62
|
+
}
|
|
63
|
+
async classify(input) {
|
|
64
|
+
return this.request("/v1/classify", { method: "POST", body: JSON.stringify(input) });
|
|
65
|
+
}
|
|
66
|
+
async benchmark(compareAlwaysFrontier = true) {
|
|
67
|
+
return this.request("/v1/benchmark/run", {
|
|
68
|
+
method: "POST",
|
|
69
|
+
body: JSON.stringify({ compare_always_frontier: compareAlwaysFrontier })
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
chat = {
|
|
73
|
+
completions: {
|
|
74
|
+
create: (request) => this.createChatCompletion(request)
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
async createChatCompletion(request) {
|
|
78
|
+
return this.request("/v1/chat/completions", {
|
|
79
|
+
method: "POST",
|
|
80
|
+
body: JSON.stringify(request)
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
async request(path, init = {}) {
|
|
84
|
+
const headers = new Headers(init.headers);
|
|
85
|
+
headers.set("Content-Type", "application/json");
|
|
86
|
+
if (this.apiKey) {
|
|
87
|
+
headers.set("Authorization", `Bearer ${this.apiKey}`);
|
|
88
|
+
} else if (this.sessionId) {
|
|
89
|
+
headers.set("X-Promptimizer-Session", this.sessionId);
|
|
90
|
+
headers.set("Authorization", `Bearer ${this.sessionId}`);
|
|
91
|
+
}
|
|
92
|
+
const response = await this.fetcher(`${this.gatewayURL}${path}`, { ...init, headers });
|
|
93
|
+
const data = await response.json().catch(() => ({}));
|
|
94
|
+
if (!response.ok) {
|
|
95
|
+
const detail = typeof data === "object" && data && "detail" in data ? String(data.detail) : response.statusText;
|
|
96
|
+
throw new PromptimizerError(detail, response.status, data);
|
|
97
|
+
}
|
|
98
|
+
return data;
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
// src/classify.ts
|
|
103
|
+
var HIGH_RISK = /* @__PURE__ */ new Set(["system_design", "safety_sensitive", "code_debug", "reasoning"]);
|
|
104
|
+
function textFrom(messages) {
|
|
105
|
+
return messages.map((m) => {
|
|
106
|
+
if (typeof m.content === "string") return m.content;
|
|
107
|
+
return m.content.map((b) => b.text ?? "").join("\n");
|
|
108
|
+
}).join("\n").trim();
|
|
109
|
+
}
|
|
110
|
+
function classifyMessages(messages) {
|
|
111
|
+
return classifyText(textFrom(messages));
|
|
112
|
+
}
|
|
113
|
+
function classifyText(text) {
|
|
114
|
+
const words = text.split(/\s+/).filter(Boolean).length;
|
|
115
|
+
const lines = text.split("\n").length;
|
|
116
|
+
const features = {
|
|
117
|
+
code_fence: /```/.test(text),
|
|
118
|
+
code_kw: /\b(def |class |function |import |fn |pub |async |SELECT |goroutine|mutex|traceback)\b/i.test(
|
|
119
|
+
text
|
|
120
|
+
),
|
|
121
|
+
math: /(\$\$|\\frac|prove that|expected value|O\([nN]\)|\d+\s*[\*\^]\s*\d+)/i.test(text),
|
|
122
|
+
design: /\b(design|architect|rate limiter|distributed|consistency|shard|1 million QPS)\b/i.test(
|
|
123
|
+
text
|
|
124
|
+
),
|
|
125
|
+
reason: /\b(prove|why does|walk through|step by step|derive|contradiction|p-value)\b/i.test(
|
|
126
|
+
text
|
|
127
|
+
),
|
|
128
|
+
debug: /\b(bug|race|panic|fails on|diagnose|deadlock)\b/i.test(text),
|
|
129
|
+
summarize: /\b(summarize|tl;dr|in two sentences|eli5)\b/i.test(text),
|
|
130
|
+
translate: /\b(translate|traduce)\b/i.test(text),
|
|
131
|
+
creative: /\b(write a (poem|story|song)|haiku)\b/i.test(text),
|
|
132
|
+
safety: /\b(refund|legal|medical|hipaa|lawsuit|diagnosis)\b/i.test(text),
|
|
133
|
+
analysis: /\b(compare|trade-?off|versus|analyse|analyze|evaluate|should we)\b/i.test(text),
|
|
134
|
+
constraints: (text.match(/\b(must|include|constraints?|requirements?)\b/gi) ?? []).length,
|
|
135
|
+
words,
|
|
136
|
+
lines,
|
|
137
|
+
question_marks: (text.match(/\?/g) ?? []).length
|
|
138
|
+
};
|
|
139
|
+
const category = categoryOf(features);
|
|
140
|
+
const complexity = complexityOf(features, category);
|
|
141
|
+
const p_small_quality = pSmallQuality(features, category, complexity);
|
|
142
|
+
const quality_risk = riskOf(category, complexity, p_small_quality);
|
|
143
|
+
const recommended_tier = tierFromP(p_small_quality);
|
|
144
|
+
const signals = [
|
|
145
|
+
features.code_fence,
|
|
146
|
+
features.code_kw,
|
|
147
|
+
features.math,
|
|
148
|
+
features.design,
|
|
149
|
+
features.reason,
|
|
150
|
+
features.debug,
|
|
151
|
+
features.safety
|
|
152
|
+
].filter(Boolean).length;
|
|
153
|
+
const confidence = category === "factual_recall" && words < 16 ? 0.9 : Math.min(0.95, 0.55 + 0.12 * signals);
|
|
154
|
+
return {
|
|
155
|
+
complexity,
|
|
156
|
+
category,
|
|
157
|
+
confidence: Number(confidence.toFixed(3)),
|
|
158
|
+
recommended_tier,
|
|
159
|
+
quality_risk,
|
|
160
|
+
p_small_quality,
|
|
161
|
+
uncertainty: Number((1 - p_small_quality).toFixed(3)),
|
|
162
|
+
structured_output: Boolean(features.code_fence || features.constraints >= 1),
|
|
163
|
+
context_tokens_est: Math.max(1, Math.round(text.length / 4)),
|
|
164
|
+
rationale: `${category.replaceAll("_", " ")} L${complexity}. P(quality|small)=${p_small_quality}. Route to ${recommended_tier}.`,
|
|
165
|
+
features
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
function categoryOf(h) {
|
|
169
|
+
if (h.safety) return "safety_sensitive";
|
|
170
|
+
if (h.design) return "system_design";
|
|
171
|
+
if (h.debug && (h.code_fence || h.code_kw)) return "code_debug";
|
|
172
|
+
if (h.code_fence || h.code_kw) return "code_generation";
|
|
173
|
+
if (h.math && h.reason) return "reasoning";
|
|
174
|
+
if (h.math) return "math";
|
|
175
|
+
if (h.reason) return "reasoning";
|
|
176
|
+
if (h.translate) return "translation";
|
|
177
|
+
if (h.summarize) return "summarization";
|
|
178
|
+
if (h.creative) return "creative";
|
|
179
|
+
if (h.analysis) return "analysis";
|
|
180
|
+
if (h.words < 24 && h.question_marks >= 1) return "factual_recall";
|
|
181
|
+
return h.words > 80 ? "analysis" : "factual_recall";
|
|
182
|
+
}
|
|
183
|
+
function complexityOf(h, category) {
|
|
184
|
+
let score = 1;
|
|
185
|
+
if (h.words > 40) score += 1;
|
|
186
|
+
if (h.words > 120) score += 1;
|
|
187
|
+
if (h.lines > 12 || h.code_fence) score += 1;
|
|
188
|
+
if (h.constraints >= 2) score += 1;
|
|
189
|
+
if (h.design || h.reason) score += 1;
|
|
190
|
+
if (h.debug) score += 1;
|
|
191
|
+
if (["system_design", "reasoning", "safety_sensitive"].includes(category)) score = Math.max(score + 1, 4);
|
|
192
|
+
if (category === "code_generation") score = Math.max(score, 3);
|
|
193
|
+
if (category === "code_debug") score = Math.max(score, 4);
|
|
194
|
+
if (category === "factual_recall" && h.words < 20) score = Math.min(score, 2);
|
|
195
|
+
return Math.max(1, Math.min(5, score));
|
|
196
|
+
}
|
|
197
|
+
function pSmallQuality(h, category, complexity) {
|
|
198
|
+
let p = 0.96;
|
|
199
|
+
if (h.design || category === "system_design") p -= 0.28;
|
|
200
|
+
if (h.safety || category === "safety_sensitive") p -= 0.3;
|
|
201
|
+
if (h.debug || category === "code_debug") p -= 0.22;
|
|
202
|
+
if (h.reason || category === "reasoning") p -= 0.18;
|
|
203
|
+
if (complexity >= 5) p -= 0.22;
|
|
204
|
+
else if (complexity >= 4) p -= 0.14;
|
|
205
|
+
else if (complexity === 3) p -= 0.06;
|
|
206
|
+
if (h.words > 120) p -= 0.07;
|
|
207
|
+
if (h.constraints >= 2) p -= 0.07;
|
|
208
|
+
if (category === "code_generation") p -= 0.05;
|
|
209
|
+
if (category === "factual_recall" && h.words < 24) p = Math.max(p, 0.94);
|
|
210
|
+
return Number(Math.min(0.99, Math.max(0.05, p)).toFixed(3));
|
|
211
|
+
}
|
|
212
|
+
function riskOf(category, complexity, p) {
|
|
213
|
+
if (HIGH_RISK.has(category) || complexity >= 5 || p < 0.72) return "high";
|
|
214
|
+
if (complexity >= 3 || p < 0.9) return "medium";
|
|
215
|
+
return "low";
|
|
216
|
+
}
|
|
217
|
+
function tierFromP(p) {
|
|
218
|
+
if (p >= 0.9) return "economy";
|
|
219
|
+
if (p >= 0.72) return "standard";
|
|
220
|
+
return "frontier";
|
|
221
|
+
}
|
|
222
|
+
function difficultyTier(complexity) {
|
|
223
|
+
if (complexity <= 2) return "economy";
|
|
224
|
+
if (complexity === 3) return "standard";
|
|
225
|
+
return "frontier";
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// src/providers.ts
|
|
229
|
+
var PROVIDERS = [
|
|
230
|
+
{ id: "openai", label: "OpenAI", baseURL: "https://api.openai.com/v1", env: "OPENAI_API_KEY", hint: "sk-..." },
|
|
231
|
+
{ id: "groq", label: "Groq", baseURL: "https://api.groq.com/openai/v1", env: "GROQ_API_KEY", hint: "gsk_..." },
|
|
232
|
+
{ id: "baseten", label: "Baseten", baseURL: "https://inference.baseten.co/v1", env: "BASETEN_API_KEY", hint: "baseten key" },
|
|
233
|
+
{ id: "openrouter", label: "OpenRouter", baseURL: "https://openrouter.ai/api/v1", env: "OPENROUTER_API_KEY", hint: "sk-or-..." },
|
|
234
|
+
{ id: "together", label: "Together", baseURL: "https://api.together.xyz/v1", env: "TOGETHER_API_KEY", hint: "together key" },
|
|
235
|
+
{ id: "fireworks", label: "Fireworks", baseURL: "https://api.fireworks.ai/inference/v1", env: "FIREWORKS_API_KEY", hint: "fw_..." },
|
|
236
|
+
{ id: "deepseek", label: "DeepSeek", baseURL: "https://api.deepseek.com/v1", env: "DEEPSEEK_API_KEY", hint: "sk-..." },
|
|
237
|
+
{ id: "mistral", label: "Mistral", baseURL: "https://api.mistral.ai/v1", env: "MISTRAL_API_KEY", hint: "mistral key" },
|
|
238
|
+
{ id: "cerebras", label: "Cerebras", baseURL: "https://api.cerebras.ai/v1", env: "CEREBRAS_API_KEY", hint: "csk-..." },
|
|
239
|
+
{ id: "xai", label: "xAI", baseURL: "https://api.x.ai/v1", env: "XAI_API_KEY", hint: "xai-..." },
|
|
240
|
+
{ id: "google", label: "Google", baseURL: "https://generativelanguage.googleapis.com/v1beta/openai", env: "GOOGLE_API_KEY", hint: "AIza..." },
|
|
241
|
+
{ id: "perplexity", label: "Perplexity", baseURL: "https://api.perplexity.ai", env: "PERPLEXITY_API_KEY", hint: "pplx-..." },
|
|
242
|
+
{ id: "nvidia", label: "NVIDIA NIM", baseURL: "https://integrate.api.nvidia.com/v1", env: "NVIDIA_API_KEY", hint: "nvapi-..." },
|
|
243
|
+
{ id: "sambanova", label: "SambaNova", baseURL: "https://api.sambanova.ai/v1", env: "SAMBANOVA_API_KEY", hint: "samba key" },
|
|
244
|
+
{ id: "hyperbolic", label: "Hyperbolic", baseURL: "https://api.hyperbolic.xyz/v1", env: "HYPERBOLIC_API_KEY", hint: "hyperbolic key" },
|
|
245
|
+
{ id: "moonshot", label: "Moonshot", baseURL: "https://api.moonshot.ai/v1", env: "MOONSHOT_API_KEY", hint: "sk-..." },
|
|
246
|
+
{ id: "ollama", label: "Ollama", baseURL: "http://localhost:11434/v1", env: "OLLAMA_API_KEY", hint: "optional" }
|
|
247
|
+
];
|
|
248
|
+
function findProvider(input) {
|
|
249
|
+
const needle = input.trim().toLowerCase();
|
|
250
|
+
return PROVIDERS.find((p) => p.id === needle || p.label.toLowerCase() === needle) ?? null;
|
|
251
|
+
}
|
|
252
|
+
function publicCatalog() {
|
|
253
|
+
return PROVIDERS.map(({ id, label, baseURL, env }) => ({
|
|
254
|
+
id,
|
|
255
|
+
label,
|
|
256
|
+
base_url: baseURL,
|
|
257
|
+
env
|
|
258
|
+
}));
|
|
259
|
+
}
|
|
260
|
+
function resolveBaseURL(input) {
|
|
261
|
+
if (input.baseURL?.trim()) return { baseURL: input.baseURL.trim().replace(/\/$/, ""), provider: findProvider(input.provider ?? "") };
|
|
262
|
+
if (input.provider) {
|
|
263
|
+
const provider = findProvider(input.provider);
|
|
264
|
+
if (provider) return { baseURL: provider.baseURL, provider };
|
|
265
|
+
}
|
|
266
|
+
return { baseURL: null, provider: null };
|
|
267
|
+
}
|
|
268
|
+
export {
|
|
269
|
+
DEFAULT_GATEWAY,
|
|
270
|
+
PROVIDERS,
|
|
271
|
+
Promptimizer,
|
|
272
|
+
PromptimizerError,
|
|
273
|
+
classifyMessages,
|
|
274
|
+
classifyText,
|
|
275
|
+
difficultyTier,
|
|
276
|
+
findProvider,
|
|
277
|
+
publicCatalog,
|
|
278
|
+
resolveBaseURL
|
|
279
|
+
};
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/providers.ts
|
|
21
|
+
var providers_exports = {};
|
|
22
|
+
__export(providers_exports, {
|
|
23
|
+
PROVIDERS: () => PROVIDERS,
|
|
24
|
+
findProvider: () => findProvider,
|
|
25
|
+
publicCatalog: () => publicCatalog,
|
|
26
|
+
resolveBaseURL: () => resolveBaseURL
|
|
27
|
+
});
|
|
28
|
+
module.exports = __toCommonJS(providers_exports);
|
|
29
|
+
var PROVIDERS = [
|
|
30
|
+
{ id: "openai", label: "OpenAI", baseURL: "https://api.openai.com/v1", env: "OPENAI_API_KEY", hint: "sk-..." },
|
|
31
|
+
{ id: "groq", label: "Groq", baseURL: "https://api.groq.com/openai/v1", env: "GROQ_API_KEY", hint: "gsk_..." },
|
|
32
|
+
{ id: "baseten", label: "Baseten", baseURL: "https://inference.baseten.co/v1", env: "BASETEN_API_KEY", hint: "baseten key" },
|
|
33
|
+
{ id: "openrouter", label: "OpenRouter", baseURL: "https://openrouter.ai/api/v1", env: "OPENROUTER_API_KEY", hint: "sk-or-..." },
|
|
34
|
+
{ id: "together", label: "Together", baseURL: "https://api.together.xyz/v1", env: "TOGETHER_API_KEY", hint: "together key" },
|
|
35
|
+
{ id: "fireworks", label: "Fireworks", baseURL: "https://api.fireworks.ai/inference/v1", env: "FIREWORKS_API_KEY", hint: "fw_..." },
|
|
36
|
+
{ id: "deepseek", label: "DeepSeek", baseURL: "https://api.deepseek.com/v1", env: "DEEPSEEK_API_KEY", hint: "sk-..." },
|
|
37
|
+
{ id: "mistral", label: "Mistral", baseURL: "https://api.mistral.ai/v1", env: "MISTRAL_API_KEY", hint: "mistral key" },
|
|
38
|
+
{ id: "cerebras", label: "Cerebras", baseURL: "https://api.cerebras.ai/v1", env: "CEREBRAS_API_KEY", hint: "csk-..." },
|
|
39
|
+
{ id: "xai", label: "xAI", baseURL: "https://api.x.ai/v1", env: "XAI_API_KEY", hint: "xai-..." },
|
|
40
|
+
{ id: "google", label: "Google", baseURL: "https://generativelanguage.googleapis.com/v1beta/openai", env: "GOOGLE_API_KEY", hint: "AIza..." },
|
|
41
|
+
{ id: "perplexity", label: "Perplexity", baseURL: "https://api.perplexity.ai", env: "PERPLEXITY_API_KEY", hint: "pplx-..." },
|
|
42
|
+
{ id: "nvidia", label: "NVIDIA NIM", baseURL: "https://integrate.api.nvidia.com/v1", env: "NVIDIA_API_KEY", hint: "nvapi-..." },
|
|
43
|
+
{ id: "sambanova", label: "SambaNova", baseURL: "https://api.sambanova.ai/v1", env: "SAMBANOVA_API_KEY", hint: "samba key" },
|
|
44
|
+
{ id: "hyperbolic", label: "Hyperbolic", baseURL: "https://api.hyperbolic.xyz/v1", env: "HYPERBOLIC_API_KEY", hint: "hyperbolic key" },
|
|
45
|
+
{ id: "moonshot", label: "Moonshot", baseURL: "https://api.moonshot.ai/v1", env: "MOONSHOT_API_KEY", hint: "sk-..." },
|
|
46
|
+
{ id: "ollama", label: "Ollama", baseURL: "http://localhost:11434/v1", env: "OLLAMA_API_KEY", hint: "optional" }
|
|
47
|
+
];
|
|
48
|
+
function findProvider(input) {
|
|
49
|
+
const needle = input.trim().toLowerCase();
|
|
50
|
+
return PROVIDERS.find((p) => p.id === needle || p.label.toLowerCase() === needle) ?? null;
|
|
51
|
+
}
|
|
52
|
+
function publicCatalog() {
|
|
53
|
+
return PROVIDERS.map(({ id, label, baseURL, env }) => ({
|
|
54
|
+
id,
|
|
55
|
+
label,
|
|
56
|
+
base_url: baseURL,
|
|
57
|
+
env
|
|
58
|
+
}));
|
|
59
|
+
}
|
|
60
|
+
function resolveBaseURL(input) {
|
|
61
|
+
if (input.baseURL?.trim()) return { baseURL: input.baseURL.trim().replace(/\/$/, ""), provider: findProvider(input.provider ?? "") };
|
|
62
|
+
if (input.provider) {
|
|
63
|
+
const provider = findProvider(input.provider);
|
|
64
|
+
if (provider) return { baseURL: provider.baseURL, provider };
|
|
65
|
+
}
|
|
66
|
+
return { baseURL: null, provider: null };
|
|
67
|
+
}
|
|
68
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
69
|
+
0 && (module.exports = {
|
|
70
|
+
PROVIDERS,
|
|
71
|
+
findProvider,
|
|
72
|
+
publicCatalog,
|
|
73
|
+
resolveBaseURL
|
|
74
|
+
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export type ProviderPreset = {
|
|
2
|
+
id: string;
|
|
3
|
+
label: string;
|
|
4
|
+
baseURL: string;
|
|
5
|
+
env: string;
|
|
6
|
+
hint: string;
|
|
7
|
+
};
|
|
8
|
+
export declare const PROVIDERS: ProviderPreset[];
|
|
9
|
+
export declare function findProvider(input: string): ProviderPreset | null;
|
|
10
|
+
export declare function publicCatalog(): {
|
|
11
|
+
id: string;
|
|
12
|
+
label: string;
|
|
13
|
+
base_url: string;
|
|
14
|
+
env: string;
|
|
15
|
+
}[];
|
|
16
|
+
export declare function resolveBaseURL(input: {
|
|
17
|
+
provider?: string;
|
|
18
|
+
baseURL?: string;
|
|
19
|
+
}): {
|
|
20
|
+
baseURL: string;
|
|
21
|
+
provider: ProviderPreset | null;
|
|
22
|
+
} | {
|
|
23
|
+
baseURL: null;
|
|
24
|
+
provider: null;
|
|
25
|
+
};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// src/providers.ts
|
|
2
|
+
var PROVIDERS = [
|
|
3
|
+
{ id: "openai", label: "OpenAI", baseURL: "https://api.openai.com/v1", env: "OPENAI_API_KEY", hint: "sk-..." },
|
|
4
|
+
{ id: "groq", label: "Groq", baseURL: "https://api.groq.com/openai/v1", env: "GROQ_API_KEY", hint: "gsk_..." },
|
|
5
|
+
{ id: "baseten", label: "Baseten", baseURL: "https://inference.baseten.co/v1", env: "BASETEN_API_KEY", hint: "baseten key" },
|
|
6
|
+
{ id: "openrouter", label: "OpenRouter", baseURL: "https://openrouter.ai/api/v1", env: "OPENROUTER_API_KEY", hint: "sk-or-..." },
|
|
7
|
+
{ id: "together", label: "Together", baseURL: "https://api.together.xyz/v1", env: "TOGETHER_API_KEY", hint: "together key" },
|
|
8
|
+
{ id: "fireworks", label: "Fireworks", baseURL: "https://api.fireworks.ai/inference/v1", env: "FIREWORKS_API_KEY", hint: "fw_..." },
|
|
9
|
+
{ id: "deepseek", label: "DeepSeek", baseURL: "https://api.deepseek.com/v1", env: "DEEPSEEK_API_KEY", hint: "sk-..." },
|
|
10
|
+
{ id: "mistral", label: "Mistral", baseURL: "https://api.mistral.ai/v1", env: "MISTRAL_API_KEY", hint: "mistral key" },
|
|
11
|
+
{ id: "cerebras", label: "Cerebras", baseURL: "https://api.cerebras.ai/v1", env: "CEREBRAS_API_KEY", hint: "csk-..." },
|
|
12
|
+
{ id: "xai", label: "xAI", baseURL: "https://api.x.ai/v1", env: "XAI_API_KEY", hint: "xai-..." },
|
|
13
|
+
{ id: "google", label: "Google", baseURL: "https://generativelanguage.googleapis.com/v1beta/openai", env: "GOOGLE_API_KEY", hint: "AIza..." },
|
|
14
|
+
{ id: "perplexity", label: "Perplexity", baseURL: "https://api.perplexity.ai", env: "PERPLEXITY_API_KEY", hint: "pplx-..." },
|
|
15
|
+
{ id: "nvidia", label: "NVIDIA NIM", baseURL: "https://integrate.api.nvidia.com/v1", env: "NVIDIA_API_KEY", hint: "nvapi-..." },
|
|
16
|
+
{ id: "sambanova", label: "SambaNova", baseURL: "https://api.sambanova.ai/v1", env: "SAMBANOVA_API_KEY", hint: "samba key" },
|
|
17
|
+
{ id: "hyperbolic", label: "Hyperbolic", baseURL: "https://api.hyperbolic.xyz/v1", env: "HYPERBOLIC_API_KEY", hint: "hyperbolic key" },
|
|
18
|
+
{ id: "moonshot", label: "Moonshot", baseURL: "https://api.moonshot.ai/v1", env: "MOONSHOT_API_KEY", hint: "sk-..." },
|
|
19
|
+
{ id: "ollama", label: "Ollama", baseURL: "http://localhost:11434/v1", env: "OLLAMA_API_KEY", hint: "optional" }
|
|
20
|
+
];
|
|
21
|
+
function findProvider(input) {
|
|
22
|
+
const needle = input.trim().toLowerCase();
|
|
23
|
+
return PROVIDERS.find((p) => p.id === needle || p.label.toLowerCase() === needle) ?? null;
|
|
24
|
+
}
|
|
25
|
+
function publicCatalog() {
|
|
26
|
+
return PROVIDERS.map(({ id, label, baseURL, env }) => ({
|
|
27
|
+
id,
|
|
28
|
+
label,
|
|
29
|
+
base_url: baseURL,
|
|
30
|
+
env
|
|
31
|
+
}));
|
|
32
|
+
}
|
|
33
|
+
function resolveBaseURL(input) {
|
|
34
|
+
if (input.baseURL?.trim()) return { baseURL: input.baseURL.trim().replace(/\/$/, ""), provider: findProvider(input.provider ?? "") };
|
|
35
|
+
if (input.provider) {
|
|
36
|
+
const provider = findProvider(input.provider);
|
|
37
|
+
if (provider) return { baseURL: provider.baseURL, provider };
|
|
38
|
+
}
|
|
39
|
+
return { baseURL: null, provider: null };
|
|
40
|
+
}
|
|
41
|
+
export {
|
|
42
|
+
PROVIDERS,
|
|
43
|
+
findProvider,
|
|
44
|
+
publicCatalog,
|
|
45
|
+
resolveBaseURL
|
|
46
|
+
};
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
export type Tier = "economy" | "standard" | "frontier";
|
|
2
|
+
export type ChatMessage = {
|
|
3
|
+
role: "system" | "user" | "assistant" | "tool" | string;
|
|
4
|
+
content: string | Array<{
|
|
5
|
+
type: string;
|
|
6
|
+
text?: string;
|
|
7
|
+
}>;
|
|
8
|
+
name?: string;
|
|
9
|
+
};
|
|
10
|
+
export type Classification = {
|
|
11
|
+
complexity: number;
|
|
12
|
+
category: string;
|
|
13
|
+
confidence: number;
|
|
14
|
+
recommended_tier: Tier;
|
|
15
|
+
quality_risk: "low" | "medium" | "high";
|
|
16
|
+
p_small_quality: number;
|
|
17
|
+
uncertainty: number;
|
|
18
|
+
structured_output: boolean;
|
|
19
|
+
context_tokens_est: number;
|
|
20
|
+
rationale: string;
|
|
21
|
+
features: Record<string, unknown>;
|
|
22
|
+
};
|
|
23
|
+
export type ModelInfo = {
|
|
24
|
+
id: string;
|
|
25
|
+
owned_by?: string;
|
|
26
|
+
input_per_1m?: number | null;
|
|
27
|
+
output_per_1m?: number | null;
|
|
28
|
+
tier: Tier;
|
|
29
|
+
source?: string;
|
|
30
|
+
selected?: boolean;
|
|
31
|
+
};
|
|
32
|
+
export type ConnectOptions = {
|
|
33
|
+
mode?: "mock" | "byok";
|
|
34
|
+
label?: string;
|
|
35
|
+
provider?: string;
|
|
36
|
+
baseURL?: string;
|
|
37
|
+
apiKey?: string;
|
|
38
|
+
accountKey?: string;
|
|
39
|
+
gatewayURL?: string;
|
|
40
|
+
};
|
|
41
|
+
export type SavingsSummary = {
|
|
42
|
+
requests: number;
|
|
43
|
+
actual_usd: number;
|
|
44
|
+
baseline_usd: number;
|
|
45
|
+
saved_usd: number;
|
|
46
|
+
saved_pct: number;
|
|
47
|
+
routing_saved_usd: number;
|
|
48
|
+
cache_saved_usd: number;
|
|
49
|
+
cache_hits: number;
|
|
50
|
+
escalations: number;
|
|
51
|
+
avg_quality: number | null;
|
|
52
|
+
recent: Array<{
|
|
53
|
+
id: string;
|
|
54
|
+
model: string;
|
|
55
|
+
tier: string;
|
|
56
|
+
actual_usd: number;
|
|
57
|
+
baseline_usd: number;
|
|
58
|
+
saved_usd: number;
|
|
59
|
+
routing_saved_usd: number;
|
|
60
|
+
cache_saved_usd: number;
|
|
61
|
+
cache_hit: boolean;
|
|
62
|
+
escalated: boolean;
|
|
63
|
+
quality: number | null;
|
|
64
|
+
created_at: string;
|
|
65
|
+
}>;
|
|
66
|
+
};
|
|
67
|
+
export type PromptimizerOptions = {
|
|
68
|
+
gatewayURL?: string;
|
|
69
|
+
sessionId?: string;
|
|
70
|
+
apiKey?: string;
|
|
71
|
+
baseURL?: string;
|
|
72
|
+
fetch?: typeof fetch;
|
|
73
|
+
};
|
|
74
|
+
export type ChatCompletionRequest = {
|
|
75
|
+
messages: ChatMessage[];
|
|
76
|
+
model?: string;
|
|
77
|
+
stream?: boolean;
|
|
78
|
+
level_override?: number;
|
|
79
|
+
temperature?: number;
|
|
80
|
+
max_tokens?: number;
|
|
81
|
+
};
|
|
82
|
+
export type CostBreakdown = {
|
|
83
|
+
actual_usd: number;
|
|
84
|
+
baseline_usd: number;
|
|
85
|
+
saved_usd: number;
|
|
86
|
+
saved_pct: number;
|
|
87
|
+
routing_saved_usd: number;
|
|
88
|
+
cache_discount_usd: number;
|
|
89
|
+
prompt_tokens: number;
|
|
90
|
+
completion_tokens: number;
|
|
91
|
+
cached_tokens: number;
|
|
92
|
+
};
|
|
93
|
+
export type ChatCompletion = {
|
|
94
|
+
id: string;
|
|
95
|
+
object: string;
|
|
96
|
+
created: number;
|
|
97
|
+
model: string;
|
|
98
|
+
choices: Array<{
|
|
99
|
+
index: number;
|
|
100
|
+
message: {
|
|
101
|
+
role: string;
|
|
102
|
+
content: string;
|
|
103
|
+
};
|
|
104
|
+
finish_reason: string;
|
|
105
|
+
}>;
|
|
106
|
+
usage: {
|
|
107
|
+
prompt_tokens: number;
|
|
108
|
+
completion_tokens: number;
|
|
109
|
+
total_tokens: number;
|
|
110
|
+
cost?: CostBreakdown;
|
|
111
|
+
};
|
|
112
|
+
promptimizer?: Record<string, unknown>;
|
|
113
|
+
};
|
|
114
|
+
export type Session = {
|
|
115
|
+
session_id: string;
|
|
116
|
+
mode: string;
|
|
117
|
+
label: string;
|
|
118
|
+
base_url: string;
|
|
119
|
+
models: ModelInfo[];
|
|
120
|
+
baseline_model: string | null;
|
|
121
|
+
stats: Record<string, number>;
|
|
122
|
+
created_at: number;
|
|
123
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "promptimizer",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "OpenAI-compatible SDK for Promptimizer — BYOK model routing, classification, and prompt caching.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./src/index.ts",
|
|
7
|
+
"module": "./src/index.ts",
|
|
8
|
+
"types": "./src/index.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./src/index.ts",
|
|
12
|
+
"import": "./src/index.ts",
|
|
13
|
+
"default": "./src/index.ts"
|
|
14
|
+
},
|
|
15
|
+
"./providers": {
|
|
16
|
+
"types": "./src/providers.ts",
|
|
17
|
+
"import": "./src/providers.ts",
|
|
18
|
+
"default": "./src/providers.ts"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"dist",
|
|
23
|
+
"README.md"
|
|
24
|
+
],
|
|
25
|
+
"scripts": {
|
|
26
|
+
"build": "node scripts/build.mjs",
|
|
27
|
+
"dev": "node scripts/build.mjs",
|
|
28
|
+
"prepublishOnly": "npm run build",
|
|
29
|
+
"typecheck": "tsc --noEmit",
|
|
30
|
+
"test": "node --experimental-strip-types --test src/classify.test.ts src/providers.test.ts",
|
|
31
|
+
"publish:npm": "npm publish --access public"
|
|
32
|
+
},
|
|
33
|
+
"publishConfig": {
|
|
34
|
+
"access": "public",
|
|
35
|
+
"main": "./dist/index.cjs",
|
|
36
|
+
"module": "./dist/index.js",
|
|
37
|
+
"types": "./dist/index.d.ts",
|
|
38
|
+
"exports": {
|
|
39
|
+
".": {
|
|
40
|
+
"types": "./dist/index.d.ts",
|
|
41
|
+
"import": "./dist/index.js",
|
|
42
|
+
"require": "./dist/index.cjs"
|
|
43
|
+
},
|
|
44
|
+
"./providers": {
|
|
45
|
+
"types": "./dist/providers.d.ts",
|
|
46
|
+
"import": "./dist/providers.js",
|
|
47
|
+
"require": "./dist/providers.cjs"
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
"repository": {
|
|
52
|
+
"type": "git",
|
|
53
|
+
"url": "git+https://github.com/sreecharan-desu/promptimizer.git",
|
|
54
|
+
"directory": "packages/sdk"
|
|
55
|
+
},
|
|
56
|
+
"homepage": "https://hackathon-omega-liart.vercel.app",
|
|
57
|
+
"bugs": {
|
|
58
|
+
"url": "https://github.com/sreecharan-desu/promptimizer/issues"
|
|
59
|
+
},
|
|
60
|
+
"keywords": [
|
|
61
|
+
"llm",
|
|
62
|
+
"openai",
|
|
63
|
+
"router",
|
|
64
|
+
"prompt-cache",
|
|
65
|
+
"byok",
|
|
66
|
+
"cost-optimization"
|
|
67
|
+
],
|
|
68
|
+
"license": "MIT",
|
|
69
|
+
"devDependencies": {
|
|
70
|
+
"@types/node": "^22.15.0",
|
|
71
|
+
"esbuild": "^0.25.9",
|
|
72
|
+
"typescript": "^5.8.0"
|
|
73
|
+
}
|
|
74
|
+
}
|