thaipass 0.1.6 → 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 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@default"),
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@default", "gemini-3.1-pro-preview", "gemini-3.7-flash", "gemini-3.1-flash-lite", "glm-5.2", "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@jts", "sonar", "sonar-reasoning-pro", "sonar-deep-research"];
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
package/dist/index.js CHANGED
@@ -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@default",
17
+ "claude-sonnet-5@azure",
18
18
  "gemini-3.1-pro-preview",
19
- "gemini-3.7-flash",
20
- "gemini-3.1-flash-lite",
21
- "glm-5.2",
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.1-flash-lite";
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 = {
@@ -301,7 +303,13 @@ const browserPostHeaders = (cookie, referer, contentType) => ({
301
303
  });
302
304
  /** Headers for a JSON action made from inside one conversation's page. */
303
305
  const conversationJsonHeaders = (cookie, conversationId) => browserPostHeaders(cookie, `${config.origin}/chat/${conversationId}`, "application/json");
304
- const loadJson = async (path, schema, cookie, signal) => {
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) => {
305
313
  let payload;
306
314
  try {
307
315
  const response = await fetch(`${config.origin}${path}`, {
@@ -309,13 +317,29 @@ const loadJson = async (path, schema, cookie, signal) => {
309
317
  redirect: "manual",
310
318
  signal
311
319
  });
312
- if (!response.ok) return null;
320
+ if (!response.ok) return {
321
+ data: null,
322
+ failure: `upstream ${response.status}`
323
+ };
313
324
  payload = await response.json();
314
325
  } catch {
315
- return null;
326
+ return {
327
+ data: null,
328
+ failure: "network"
329
+ };
316
330
  }
317
331
  const decoded = schema.safeParse(payload);
318
- return decoded.success ? decoded.data : null;
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;
319
343
  };
320
344
  //#endregion
321
345
  //#region ../core/src/aipass/catalog.ts
@@ -355,22 +379,36 @@ const reportDrift = (catalog) => {
355
379
  });
356
380
  };
357
381
  const load = async (cookie, signal) => {
358
- const listed = await loadJson(CATALOG_PATH, catalogSchema, cookie, signal);
359
- if (!listed) return null;
360
- return new Map(listed.data.map((entry) => [entry.id, {
361
- free: entry.isFreeCredit ?? false,
362
- ready: entry.ready ?? true,
363
- thinking: entry.thinkingConfig?.supportedLevels ?? null
364
- }]));
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
+ };
365
395
  };
366
- const fetchCatalog = async (clientId, cookie, signal) => {
396
+ /** The catalog with the reason it is missing, for a caller that reports it. */
397
+ const fetchCatalogResult = async (clientId, cookie, signal) => {
367
398
  const cached = cache.get(clientId);
368
- if (cached) return cached;
369
- const catalog = await load(cookie, signal);
370
- if (!catalog) return null;
371
- cache.set(clientId, catalog);
372
- reportDrift(catalog);
373
- return catalog;
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;
374
412
  };
375
413
  //#endregion
376
414
  //#region ../core/src/aipass/refusal.ts
@@ -1160,12 +1198,29 @@ const roleLabel = (turn, names) => {
1160
1198
  const turnText = (turn) => {
1161
1199
  return [turn.content.trim(), ...(turn.calls ?? []).map(renderCall)].filter((part) => part.length > 0).join("\n\n");
1162
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.";
1163
1217
  const flattenPrompt = ({ tools, turns }) => {
1164
1218
  const system = turns.filter((turn) => turn.role === "system").map((turn) => turn.content).filter((text) => text.length > 0).join("\n\n");
1165
1219
  const convo = turns.filter((turn) => turn.role !== "system");
1166
1220
  if (system.length === 0 && tools.length === 0 && convo.length === 1 && convo[0]?.role === "user" && convo[0].calls === void 0) return convo[0].content;
1167
1221
  const blocks = [];
1168
1222
  if (system.length > 0) blocks.push(system.trim());
1223
+ else if (tools.length > 0) blocks.push(IMPLIED_SYSTEM);
1169
1224
  if (tools.length > 0) blocks.push(renderToolGuide(tools));
1170
1225
  const names = toolNames(convo);
1171
1226
  const lines = [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "thaipass",
3
- "version": "0.1.6",
3
+ "version": "0.1.7",
4
4
  "description": "AI SDK provider for AI Pass, using your own session cookie.",
5
5
  "keywords": [
6
6
  "ai-sdk",