thaipass 0.1.5 → 0.1.7
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 +1 -1
- package/dist/index.d.ts +5 -2
- package/dist/index.js +260 -27
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -13,7 +13,7 @@ import { createAipass } from "thaipass";
|
|
|
13
13
|
const aipass = createAipass({ cookie: process.env.AIPASS_COOKIE ?? "" });
|
|
14
14
|
|
|
15
15
|
const result = streamText({
|
|
16
|
-
model: aipass("claude-sonnet-5@
|
|
16
|
+
model: aipass("claude-sonnet-5@azure"),
|
|
17
17
|
prompt: "hi",
|
|
18
18
|
});
|
|
19
19
|
```
|
package/dist/index.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ import { z } from "zod";
|
|
|
8
8
|
* drift warning. A media id needs per-model knowledge the catalog does not
|
|
9
9
|
* carry, so the media lists below stay the gate for their routes.
|
|
10
10
|
*/
|
|
11
|
-
declare const CHAT_MODELS: readonly ["gpt-5.6-terra", "gpt-5.6-sol", "claude-opus-5@azure", "claude-sonnet-5@
|
|
11
|
+
declare const CHAT_MODELS: readonly ["gpt-5.6-terra", "gpt-5.6-sol", "claude-opus-5@azure", "claude-sonnet-5@azure", "gemini-3.1-pro-preview", "gemini-3.8-flash", "gemini-3.5-flash-lite", "glm-5.3", "grok-4.3", "DeepSeek-V3.2", "minimax-m2-maas", "qwen3-next-80b-a3b-instruct-maas", "Kimi-K2.7-Code", "Mistral-Large-3", "Mistral-Medium-3", "Llama-4-Scout-17B-16E-Instruct-1", "Llama-4-Maverick-17B-128E-Instruct-FP8-1", "pathumma-thaillm-8b", "openai-deep-research", "openthai2.0-legal", "openthai2.0-legal@jts", "sonar", "sonar-reasoning-pro", "sonar-deep-research"];
|
|
12
12
|
type KnownChatModel = (typeof CHAT_MODELS)[number];
|
|
13
13
|
//#endregion
|
|
14
14
|
//#region ../core/src/lib/config.d.ts
|
|
@@ -24,7 +24,10 @@ interface UpstreamLogger {
|
|
|
24
24
|
/** The known ids complete in an editor; any other string is left to the catalog. */
|
|
25
25
|
export type AipassModelId = KnownChatModel | (string & Record<never, never>);
|
|
26
26
|
export interface AipassProviderSettings {
|
|
27
|
-
/**
|
|
27
|
+
/**
|
|
28
|
+
* The Cookie header of a browser signed in to AI Pass, or a thaipass token
|
|
29
|
+
* when this process holds the `THAIPASS_TOKEN_KEY` that sealed it.
|
|
30
|
+
*/
|
|
28
31
|
readonly cookie: string;
|
|
29
32
|
/** Process-wide; defaults to https://de.aipass.net. */
|
|
30
33
|
readonly origin?: string;
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { APICallError, NoSuchModelError } from "@ai-sdk/provider";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
-
import { createHash } from "node:crypto";
|
|
3
|
+
import { createDecipheriv, createHash } from "node:crypto";
|
|
4
4
|
import { parseJsonEventStream } from "@ai-sdk/provider-utils";
|
|
5
5
|
//#region ../core/src/aipass/models.ts
|
|
6
6
|
/**
|
|
@@ -14,11 +14,11 @@ const CHAT_MODELS = [
|
|
|
14
14
|
"gpt-5.6-terra",
|
|
15
15
|
"gpt-5.6-sol",
|
|
16
16
|
"claude-opus-5@azure",
|
|
17
|
-
"claude-sonnet-5@
|
|
17
|
+
"claude-sonnet-5@azure",
|
|
18
18
|
"gemini-3.1-pro-preview",
|
|
19
|
-
"gemini-3.
|
|
20
|
-
"gemini-3.
|
|
21
|
-
"glm-5.
|
|
19
|
+
"gemini-3.8-flash",
|
|
20
|
+
"gemini-3.5-flash-lite",
|
|
21
|
+
"glm-5.3",
|
|
22
22
|
"grok-4.3",
|
|
23
23
|
"DeepSeek-V3.2",
|
|
24
24
|
"minimax-m2-maas",
|
|
@@ -30,6 +30,7 @@ const CHAT_MODELS = [
|
|
|
30
30
|
"Llama-4-Maverick-17B-128E-Instruct-FP8-1",
|
|
31
31
|
"pathumma-thaillm-8b",
|
|
32
32
|
"openai-deep-research",
|
|
33
|
+
"openthai2.0-legal",
|
|
33
34
|
"openthai2.0-legal@jts",
|
|
34
35
|
"sonar",
|
|
35
36
|
"sonar-reasoning-pro",
|
|
@@ -43,6 +44,7 @@ const CHAT_MODELS = [
|
|
|
43
44
|
const IMAGE_MODELS = [
|
|
44
45
|
"gpt-image-2",
|
|
45
46
|
"gemini-3-pro-image",
|
|
47
|
+
"gemini-3.1-flash-image",
|
|
46
48
|
"gemini-2.5-flash-image",
|
|
47
49
|
"seedream-4.0",
|
|
48
50
|
"seedream-5.0-lite"
|
|
@@ -72,7 +74,7 @@ z.string().min(1, { error: "model must not be empty, see GET /v1/models" }).meta
|
|
|
72
74
|
description: "A chat model id from GET /v1/models. Ids are case-sensitive and Claude carries a @provider suffix.",
|
|
73
75
|
examples: [...CHAT_MODELS]
|
|
74
76
|
});
|
|
75
|
-
const DEFAULT_MODEL = "gemini-3.
|
|
77
|
+
const DEFAULT_MODEL = "gemini-3.5-flash-lite";
|
|
76
78
|
const ANY_MODELS = [...CHAT_MODELS, ...MEDIA_MODELS];
|
|
77
79
|
z.enum(ANY_MODELS, { error: "unknown model, see GET /v1/models" });
|
|
78
80
|
const current = {
|
|
@@ -86,6 +88,185 @@ const configure = (changes) => {
|
|
|
86
88
|
Object.assign(current, changes);
|
|
87
89
|
};
|
|
88
90
|
//#endregion
|
|
91
|
+
//#region ../core/src/auth/seal.ts
|
|
92
|
+
/**
|
|
93
|
+
* Login with thaipass, without a database.
|
|
94
|
+
*
|
|
95
|
+
* An app that wants to talk to this gateway has to prove it may drive someone's
|
|
96
|
+
* AI Pass account. The obvious way is to hand it the session cookie, which is
|
|
97
|
+
* what every client does today: the key in a Codex config or a Claude Code
|
|
98
|
+
* environment variable is the whole account, it cannot be revoked, and it has
|
|
99
|
+
* to be copied again by hand each time AI Pass rotates it.
|
|
100
|
+
*
|
|
101
|
+
* A thaipass token is that cookie sealed under a key only the gateway holds.
|
|
102
|
+
* The app carries the sealed bytes and can read nothing in them; the gateway
|
|
103
|
+
* unseals per request and forwards the cookie upstream as before. Nothing is
|
|
104
|
+
* stored anywhere, so a deployment stays as stateless as it is now, and the
|
|
105
|
+
* promise the README makes — that the gateway keeps no credential — still
|
|
106
|
+
* holds: what it keeps is the key that opens one, not the credential.
|
|
107
|
+
*
|
|
108
|
+
* The same envelope carries the authorization code in the middle of a login,
|
|
109
|
+
* with the PKCE challenge and the app's redirect inside it, so a code cannot be
|
|
110
|
+
* replayed as an access token or spent by another app.
|
|
111
|
+
*/
|
|
112
|
+
const ALGORITHM = "aes-256-gcm";
|
|
113
|
+
const IV_BYTES = 12;
|
|
114
|
+
const TAG_BYTES = 16;
|
|
115
|
+
const KEY_BYTES = 32;
|
|
116
|
+
const TOKEN_PREFIX = "tp_v1_";
|
|
117
|
+
const CODE_PREFIX = "tp_c1_";
|
|
118
|
+
/** The wire shape, with short names because the envelope travels in a header. */
|
|
119
|
+
const payloadSchema = z.object({
|
|
120
|
+
a: z.string().optional(),
|
|
121
|
+
c: z.string(),
|
|
122
|
+
h: z.string().optional(),
|
|
123
|
+
r: z.string().optional(),
|
|
124
|
+
s: z.string().optional(),
|
|
125
|
+
sc: z.string().optional(),
|
|
126
|
+
x: z.number()
|
|
127
|
+
});
|
|
128
|
+
const SECOND_MS = 1e3;
|
|
129
|
+
/** Bytes that authenticated under our own key are still parsed, not trusted. */
|
|
130
|
+
const openPayload = (plain) => {
|
|
131
|
+
try {
|
|
132
|
+
return payloadSchema.parse(JSON.parse(plain));
|
|
133
|
+
} catch {
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
const NO_KEY$1 = "this deployment issues no thaipass tokens: set THAIPASS_TOKEN_KEY to a 32 byte base64 key";
|
|
138
|
+
const MALFORMED = "the token is not a thaipass token";
|
|
139
|
+
const TAMPERED = "the token does not open: it is for another deployment, or it was altered";
|
|
140
|
+
const EXPIRED = "the token has expired, sign in again";
|
|
141
|
+
const prefixFor = (purpose) => purpose === "code" ? CODE_PREFIX : TOKEN_PREFIX;
|
|
142
|
+
/**
|
|
143
|
+
* The key as bytes, or null when this deployment was never given one. A
|
|
144
|
+
* missing key is not an error: a personal gateway that only ever sees raw
|
|
145
|
+
* cookies needs none, and every path here falls back to that.
|
|
146
|
+
*/
|
|
147
|
+
const tokenKey = () => {
|
|
148
|
+
const raw = process.env.THAIPASS_TOKEN_KEY?.trim();
|
|
149
|
+
if (!raw) return null;
|
|
150
|
+
const key = Buffer.from(raw, "base64");
|
|
151
|
+
return key.length === KEY_BYTES ? key : null;
|
|
152
|
+
};
|
|
153
|
+
const issuesTokens = () => tokenKey() !== null;
|
|
154
|
+
const isSealed = (value, purpose = "access") => value.startsWith(prefixFor(purpose));
|
|
155
|
+
const unseal = (value, purpose = "access") => {
|
|
156
|
+
const prefix = prefixFor(purpose);
|
|
157
|
+
if (!value.startsWith(prefix)) return {
|
|
158
|
+
ok: false,
|
|
159
|
+
reason: MALFORMED
|
|
160
|
+
};
|
|
161
|
+
const key = tokenKey();
|
|
162
|
+
if (!key) return {
|
|
163
|
+
ok: false,
|
|
164
|
+
reason: NO_KEY$1
|
|
165
|
+
};
|
|
166
|
+
const sealed = Buffer.from(value.slice(prefix.length), "base64url");
|
|
167
|
+
if (sealed.length <= 28) return {
|
|
168
|
+
ok: false,
|
|
169
|
+
reason: MALFORMED
|
|
170
|
+
};
|
|
171
|
+
const iv = sealed.subarray(0, IV_BYTES);
|
|
172
|
+
const body = sealed.subarray(IV_BYTES, sealed.length - TAG_BYTES);
|
|
173
|
+
const tag = sealed.subarray(sealed.length - TAG_BYTES);
|
|
174
|
+
let plain;
|
|
175
|
+
try {
|
|
176
|
+
const decipher = createDecipheriv(ALGORITHM, key, iv);
|
|
177
|
+
decipher.setAAD(Buffer.from(purpose, "utf-8"));
|
|
178
|
+
decipher.setAuthTag(tag);
|
|
179
|
+
plain = decipher.update(body, void 0, "utf-8") + decipher.final("utf-8");
|
|
180
|
+
} catch {
|
|
181
|
+
return {
|
|
182
|
+
ok: false,
|
|
183
|
+
reason: TAMPERED
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
const payload = openPayload(plain);
|
|
187
|
+
if (payload === null) return {
|
|
188
|
+
ok: false,
|
|
189
|
+
reason: TAMPERED
|
|
190
|
+
};
|
|
191
|
+
if (payload.x * SECOND_MS <= Date.now()) return {
|
|
192
|
+
ok: false,
|
|
193
|
+
reason: EXPIRED
|
|
194
|
+
};
|
|
195
|
+
return {
|
|
196
|
+
claims: {
|
|
197
|
+
clientId: payload.a,
|
|
198
|
+
codeChallenge: payload.h,
|
|
199
|
+
cookie: payload.c,
|
|
200
|
+
expiresAt: payload.x,
|
|
201
|
+
redirectUri: payload.r,
|
|
202
|
+
scope: payload.sc,
|
|
203
|
+
subject: payload.s
|
|
204
|
+
},
|
|
205
|
+
ok: true
|
|
206
|
+
};
|
|
207
|
+
};
|
|
208
|
+
//#endregion
|
|
209
|
+
//#region ../core/src/aipass/session.ts
|
|
210
|
+
const SESSION_TOKEN = "__Secure-ai_passport_auth.session_token";
|
|
211
|
+
const NO_TOKEN = `the credential carries no ${SESSION_TOKEN}, send the whole Cookie header from a logged-in browser session rather than the token on its own`;
|
|
212
|
+
const withToken = (cookie, grant) => {
|
|
213
|
+
if (!cookie.includes(SESSION_TOKEN)) return {
|
|
214
|
+
ok: false,
|
|
215
|
+
reason: NO_TOKEN
|
|
216
|
+
};
|
|
217
|
+
return grant ? {
|
|
218
|
+
cookie,
|
|
219
|
+
grant,
|
|
220
|
+
ok: true
|
|
221
|
+
} : {
|
|
222
|
+
cookie,
|
|
223
|
+
ok: true
|
|
224
|
+
};
|
|
225
|
+
};
|
|
226
|
+
/**
|
|
227
|
+
* Two credentials reach the same account. A thaipass token is the cookie
|
|
228
|
+
* sealed under this deployment's key, which is what `thaipass login` hands an
|
|
229
|
+
* app; a raw Cookie header is what a personal setup has always sent. Unsealing
|
|
230
|
+
* happens here, once, so every route accepts either without knowing about it.
|
|
231
|
+
*/
|
|
232
|
+
const resolve = (value) => {
|
|
233
|
+
const credential = value.trim();
|
|
234
|
+
if (!isSealed(credential)) return withToken(credential);
|
|
235
|
+
const opened = unseal(credential);
|
|
236
|
+
if (!opened.ok) return {
|
|
237
|
+
ok: false,
|
|
238
|
+
reason: opened.reason
|
|
239
|
+
};
|
|
240
|
+
const { claims } = opened;
|
|
241
|
+
return withToken(claims.cookie, {
|
|
242
|
+
clientId: claims.clientId,
|
|
243
|
+
expiresAt: claims.expiresAt,
|
|
244
|
+
scope: claims.scope,
|
|
245
|
+
subject: claims.subject
|
|
246
|
+
});
|
|
247
|
+
};
|
|
248
|
+
/** A credential handed over directly, as the CLI reads it from the environment or a file. */
|
|
249
|
+
const cookieFromValue = (value) => resolve(value);
|
|
250
|
+
const CLIENT_ID_LENGTH = 16;
|
|
251
|
+
const clientIdFromCookie = (cookie) => createHash("sha256").update(cookie).digest("hex").slice(0, CLIENT_ID_LENGTH);
|
|
252
|
+
//#endregion
|
|
253
|
+
//#region src/credential.ts
|
|
254
|
+
/**
|
|
255
|
+
* What `createAipass` will actually send upstream.
|
|
256
|
+
*
|
|
257
|
+
* `thaipass login` hands people a `tp_…` token now, so one will be pasted in
|
|
258
|
+
* here sooner or later. The provider is not a gateway — it talks to AI Pass
|
|
259
|
+
* directly — so a token is only usable in a process that also holds the key
|
|
260
|
+
* that sealed it. When it does, the token opens; when it does not, saying so
|
|
261
|
+
* beats letting AI Pass refuse the request for reasons of its own.
|
|
262
|
+
*/
|
|
263
|
+
const NO_KEY = "that is a thaipass token, and this provider talks to AI Pass directly. Give it the Cookie header, or set THAIPASS_TOKEN_KEY to the key that sealed the token.";
|
|
264
|
+
const resolveCredential = (value) => {
|
|
265
|
+
const lookup = cookieFromValue(value);
|
|
266
|
+
if (lookup.ok) return lookup.cookie;
|
|
267
|
+
throw new Error(isSealed(value) && !issuesTokens() ? NO_KEY : lookup.reason);
|
|
268
|
+
};
|
|
269
|
+
//#endregion
|
|
89
270
|
//#region ../core/src/lib/cache.ts
|
|
90
271
|
const ttlCache = (ttlMs) => {
|
|
91
272
|
const entries = /* @__PURE__ */ new Map();
|
|
@@ -122,7 +303,13 @@ const browserPostHeaders = (cookie, referer, contentType) => ({
|
|
|
122
303
|
});
|
|
123
304
|
/** Headers for a JSON action made from inside one conversation's page. */
|
|
124
305
|
const conversationJsonHeaders = (cookie, conversationId) => browserPostHeaders(cookie, `${config.origin}/chat/${conversationId}`, "application/json");
|
|
125
|
-
|
|
306
|
+
/**
|
|
307
|
+
* The same GET as {@link loadJson}, keeping why it failed. A caller that
|
|
308
|
+
* answers an HTTP request needs the reason: "no catalog" reads identically
|
|
309
|
+
* whether the cookie is dead, the network blinked, or upstream renamed a
|
|
310
|
+
* field, and those want three different fixes.
|
|
311
|
+
*/
|
|
312
|
+
const loadJsonResult = async (path, schema, cookie, signal) => {
|
|
126
313
|
let payload;
|
|
127
314
|
try {
|
|
128
315
|
const response = await fetch(`${config.origin}${path}`, {
|
|
@@ -130,13 +317,29 @@ const loadJson = async (path, schema, cookie, signal) => {
|
|
|
130
317
|
redirect: "manual",
|
|
131
318
|
signal
|
|
132
319
|
});
|
|
133
|
-
if (!response.ok) return
|
|
320
|
+
if (!response.ok) return {
|
|
321
|
+
data: null,
|
|
322
|
+
failure: `upstream ${response.status}`
|
|
323
|
+
};
|
|
134
324
|
payload = await response.json();
|
|
135
325
|
} catch {
|
|
136
|
-
return
|
|
326
|
+
return {
|
|
327
|
+
data: null,
|
|
328
|
+
failure: "network"
|
|
329
|
+
};
|
|
137
330
|
}
|
|
138
331
|
const decoded = schema.safeParse(payload);
|
|
139
|
-
return decoded.success ?
|
|
332
|
+
return decoded.success ? {
|
|
333
|
+
data: decoded.data,
|
|
334
|
+
failure: null
|
|
335
|
+
} : {
|
|
336
|
+
data: null,
|
|
337
|
+
failure: "schema"
|
|
338
|
+
};
|
|
339
|
+
};
|
|
340
|
+
/** The body alone, for a loader whose caller has nowhere to put the reason. */
|
|
341
|
+
const loadJson = async (path, schema, cookie, signal) => {
|
|
342
|
+
return (await loadJsonResult(path, schema, cookie, signal)).data;
|
|
140
343
|
};
|
|
141
344
|
//#endregion
|
|
142
345
|
//#region ../core/src/aipass/catalog.ts
|
|
@@ -176,22 +379,36 @@ const reportDrift = (catalog) => {
|
|
|
176
379
|
});
|
|
177
380
|
};
|
|
178
381
|
const load = async (cookie, signal) => {
|
|
179
|
-
const listed = await
|
|
180
|
-
if (!listed) return
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
382
|
+
const { data: listed, failure } = await loadJsonResult(CATALOG_PATH, catalogSchema, cookie, signal);
|
|
383
|
+
if (!listed) return {
|
|
384
|
+
catalog: null,
|
|
385
|
+
failure
|
|
386
|
+
};
|
|
387
|
+
return {
|
|
388
|
+
catalog: new Map(listed.data.map((entry) => [entry.id, {
|
|
389
|
+
free: entry.isFreeCredit ?? false,
|
|
390
|
+
ready: entry.ready ?? true,
|
|
391
|
+
thinking: entry.thinkingConfig?.supportedLevels ?? null
|
|
392
|
+
}])),
|
|
393
|
+
failure: null
|
|
394
|
+
};
|
|
186
395
|
};
|
|
187
|
-
|
|
396
|
+
/** The catalog with the reason it is missing, for a caller that reports it. */
|
|
397
|
+
const fetchCatalogResult = async (clientId, cookie, signal) => {
|
|
188
398
|
const cached = cache.get(clientId);
|
|
189
|
-
if (cached) return
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
return
|
|
399
|
+
if (cached) return {
|
|
400
|
+
catalog: cached,
|
|
401
|
+
failure: null
|
|
402
|
+
};
|
|
403
|
+
const loaded = await load(cookie, signal);
|
|
404
|
+
if (!loaded.catalog) return loaded;
|
|
405
|
+
cache.set(clientId, loaded.catalog);
|
|
406
|
+
reportDrift(loaded.catalog);
|
|
407
|
+
return loaded;
|
|
408
|
+
};
|
|
409
|
+
/** The catalog alone, for a caller with nowhere to put the reason. */
|
|
410
|
+
const fetchCatalog = async (clientId, cookie, signal) => {
|
|
411
|
+
return (await fetchCatalogResult(clientId, cookie, signal)).catalog;
|
|
195
412
|
};
|
|
196
413
|
//#endregion
|
|
197
414
|
//#region ../core/src/aipass/refusal.ts
|
|
@@ -541,8 +758,6 @@ const settleCredits = async (cookie, before) => {
|
|
|
541
758
|
usage: toCreditUsage(start, after)
|
|
542
759
|
};
|
|
543
760
|
};
|
|
544
|
-
const CLIENT_ID_LENGTH = 16;
|
|
545
|
-
const clientIdFromCookie = (cookie) => createHash("sha256").update(cookie).digest("hex").slice(0, CLIENT_ID_LENGTH);
|
|
546
761
|
const thinkingLevelSchema = z.enum([
|
|
547
762
|
"low",
|
|
548
763
|
"medium",
|
|
@@ -983,12 +1198,29 @@ const roleLabel = (turn, names) => {
|
|
|
983
1198
|
const turnText = (turn) => {
|
|
984
1199
|
return [turn.content.trim(), ...(turn.calls ?? []).map(renderCall)].filter((part) => part.length > 0).join("\n\n");
|
|
985
1200
|
};
|
|
1201
|
+
/**
|
|
1202
|
+
* Stands in for a caller who sent no system message, so the tool guide below
|
|
1203
|
+
* it reads as instruction rather than as a description of tools that live
|
|
1204
|
+
* somewhere else.
|
|
1205
|
+
*
|
|
1206
|
+
* Measured 2026-09-19 against ten models, one request at a time with the
|
|
1207
|
+
* conditions interleaved, five rounds each: with a single tool attached and
|
|
1208
|
+
* no system message, `gpt-5.6-sol` and `gpt-5.6-terra` never called it,
|
|
1209
|
+
* `gemini-3.1-pro-preview` and `glm-5.3` managed 2/5, `Kimi-K2.7-Code` 3/5
|
|
1210
|
+
* and `grok-4.3` 4/5. `gpt-5.6-sol` said why: "I can't access the
|
|
1211
|
+
* select_choice tool here". It could see the name, so the guide had arrived.
|
|
1212
|
+
* With one line of system ahead of it, all ten called the tool on every
|
|
1213
|
+
* round. Graders in the autoevals shape send one user message and no system
|
|
1214
|
+
* message, which is how this surfaced.
|
|
1215
|
+
*/
|
|
1216
|
+
const IMPLIED_SYSTEM = "You are an assistant with the tools described below. Call them when they apply.";
|
|
986
1217
|
const flattenPrompt = ({ tools, turns }) => {
|
|
987
1218
|
const system = turns.filter((turn) => turn.role === "system").map((turn) => turn.content).filter((text) => text.length > 0).join("\n\n");
|
|
988
1219
|
const convo = turns.filter((turn) => turn.role !== "system");
|
|
989
1220
|
if (system.length === 0 && tools.length === 0 && convo.length === 1 && convo[0]?.role === "user" && convo[0].calls === void 0) return convo[0].content;
|
|
990
1221
|
const blocks = [];
|
|
991
1222
|
if (system.length > 0) blocks.push(system.trim());
|
|
1223
|
+
else if (tools.length > 0) blocks.push(IMPLIED_SYSTEM);
|
|
992
1224
|
if (tools.length > 0) blocks.push(renderToolGuide(tools));
|
|
993
1225
|
const names = toolNames(convo);
|
|
994
1226
|
const lines = [];
|
|
@@ -1473,6 +1705,7 @@ const aipassModel = (cookie, modelId) => ({
|
|
|
1473
1705
|
//#endregion
|
|
1474
1706
|
//#region src/index.ts
|
|
1475
1707
|
const createAipass = (settings) => {
|
|
1708
|
+
const cookie = resolveCredential(settings.cookie);
|
|
1476
1709
|
if (settings.origin !== void 0) configure({ origin: settings.origin });
|
|
1477
1710
|
if (settings.logger !== void 0) configure({ logger: settings.logger });
|
|
1478
1711
|
const languageModel = (modelId = DEFAULT_MODEL) => {
|
|
@@ -1480,7 +1713,7 @@ const createAipass = (settings) => {
|
|
|
1480
1713
|
modelId,
|
|
1481
1714
|
modelType: "languageModel"
|
|
1482
1715
|
});
|
|
1483
|
-
return aipassModel(
|
|
1716
|
+
return aipassModel(cookie, modelId);
|
|
1484
1717
|
};
|
|
1485
1718
|
return Object.assign(languageModel, { languageModel });
|
|
1486
1719
|
};
|