@d-ai/pi 0.2.1 → 0.2.3

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.
Files changed (3) hide show
  1. package/README.md +1 -1
  2. package/dist/index.js +159 -8
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -21,7 +21,7 @@ Set a D.AI API key:
21
21
  export DAI_API_KEY=ddsk_...
22
22
  ```
23
23
 
24
- Or in Pi run `/login`, choose **D.AI**, and paste `ddsk_...`. That discovers chat models from `GET /v1/models` and media models from the public catalog. Then pick `dai/<model>` in `/model`.
24
+ Or in Pi run `/login`, choose **D.AI**, and paste `ddsk_...`. That discovers chat models from `GET /v1/models` and media models from the public catalog. Then pick `dai/<model>` in `/model`. GPT-5.6 / GPT-6 expose thinking levels (`low` … `max`); `gpt-6-astra` cannot turn thinking off.
25
25
 
26
26
  `/dai key` also writes `~/.pi/agent/dai.json`. Optional `baseUrl` defaults to `https://dai.itbug.shop`.
27
27
 
package/dist/index.js CHANGED
@@ -1017,6 +1017,10 @@ function toUserError(error) {
1017
1017
  return new DaiPluginError("Invalid D.AI API key.");
1018
1018
  }
1019
1019
  if (error.status === 402 || /余额不足|insufficient_quota/iu.test(error.message)) {
1020
+ const text = sanitize(publicMessage(error));
1021
+ if (text.includes("\u9884\u6263")) {
1022
+ return new DaiPluginError(text);
1023
+ }
1020
1024
  return new DaiPluginError("D.AI \u4F59\u989D\u4E0D\u8DB3\u3002");
1021
1025
  }
1022
1026
  if (error.status >= 400 && error.status < 500) {
@@ -1042,6 +1046,34 @@ function sanitize(message) {
1042
1046
  function configPath() {
1043
1047
  return join(homedir(), ".pi", "agent", "dai.json");
1044
1048
  }
1049
+ function authJsonPath() {
1050
+ return join(homedir(), ".pi", "agent", "auth.json");
1051
+ }
1052
+ async function loadAuthJsonKey(path = authJsonPath()) {
1053
+ try {
1054
+ const raw = JSON.parse(await readFile(path, "utf8"));
1055
+ if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
1056
+ return void 0;
1057
+ }
1058
+ const dai = raw.dai;
1059
+ if (typeof dai !== "object" || dai === null || Array.isArray(dai)) {
1060
+ return void 0;
1061
+ }
1062
+ const record = dai;
1063
+ for (const field of ["key", "access"]) {
1064
+ const value = record[field];
1065
+ if (typeof value === "string" && value.trim()) {
1066
+ return value.trim();
1067
+ }
1068
+ }
1069
+ return void 0;
1070
+ } catch (error) {
1071
+ if (isMissingFile(error)) {
1072
+ return void 0;
1073
+ }
1074
+ throw error;
1075
+ }
1076
+ }
1045
1077
  async function loadFileConfig(path = configPath()) {
1046
1078
  try {
1047
1079
  const raw = JSON.parse(await readFile(path, "utf8"));
@@ -1071,17 +1103,24 @@ async function saveFileConfig(config, path = configPath()) {
1071
1103
  await writeFile(`${path}`, `${JSON.stringify(next, null, 2)}
1072
1104
  `, { mode: 384 });
1073
1105
  }
1074
- async function resolveConfig(env = process.env, path = configPath()) {
1106
+ async function resolveConfig(env = process.env, path = configPath(), authPath = authJsonPath()) {
1075
1107
  const file = await loadFileConfig(path);
1076
- const apiKey = firstNonEmpty(file.apiKey, env.DAI_API_KEY);
1108
+ const fromAuth = await loadAuthJsonKey(authPath);
1109
+ const apiKey = firstNonEmpty(file.apiKey, env.DAI_API_KEY, fromAuth);
1077
1110
  if (!apiKey) {
1078
1111
  throw missingApiKeyError();
1079
1112
  }
1113
+ if (!file.apiKey && fromAuth) {
1114
+ await saveFileConfig({ apiKey: fromAuth }, path);
1115
+ }
1080
1116
  const baseUrl = firstNonEmpty(file.baseUrl, env.DAI_BASE_URL);
1081
1117
  return baseUrl === void 0 ? { apiKey } : { apiKey, baseUrl };
1082
1118
  }
1083
- function hasApiKey(config, env = process.env) {
1084
- return Boolean(firstNonEmpty(config.apiKey, env.DAI_API_KEY));
1119
+ async function hasApiKey(config, env = process.env, authPath = authJsonPath()) {
1120
+ if (firstNonEmpty(config.apiKey, env.DAI_API_KEY)) {
1121
+ return true;
1122
+ }
1123
+ return Boolean(await loadAuthJsonKey(authPath));
1085
1124
  }
1086
1125
  function firstNonEmpty(...values) {
1087
1126
  for (const value of values) {
@@ -1102,6 +1141,115 @@ function normalizeOrigin(baseUrl) {
1102
1141
  return baseUrl.replace(/\/+$/u, "").replace(/\/v1$/u, "");
1103
1142
  }
1104
1143
 
1144
+ // src/thinking.ts
1145
+ var GPT_5_6 = {
1146
+ off: "none",
1147
+ minimal: null,
1148
+ low: "low",
1149
+ medium: "medium",
1150
+ high: "high",
1151
+ xhigh: "xhigh",
1152
+ max: "max"
1153
+ };
1154
+ var GPT_6 = {
1155
+ off: null,
1156
+ minimal: null,
1157
+ low: "low",
1158
+ medium: "medium",
1159
+ high: "high",
1160
+ xhigh: "xhigh",
1161
+ max: "max"
1162
+ };
1163
+ var GPT_5_4 = {
1164
+ off: "none",
1165
+ minimal: null,
1166
+ low: "low",
1167
+ medium: "medium",
1168
+ high: "high",
1169
+ xhigh: "xhigh",
1170
+ max: null
1171
+ };
1172
+ var GPT_5_1 = {
1173
+ off: "none",
1174
+ minimal: null,
1175
+ low: "low",
1176
+ medium: "medium",
1177
+ high: "high",
1178
+ xhigh: null,
1179
+ max: null
1180
+ };
1181
+ var GPT_5 = {
1182
+ off: null,
1183
+ minimal: "minimal",
1184
+ low: "low",
1185
+ medium: "medium",
1186
+ high: "high",
1187
+ xhigh: null,
1188
+ max: null
1189
+ };
1190
+ var O_SERIES = {
1191
+ off: null,
1192
+ minimal: null,
1193
+ low: "low",
1194
+ medium: "medium",
1195
+ high: "high",
1196
+ xhigh: null,
1197
+ max: null
1198
+ };
1199
+ var KNOWN = {
1200
+ "gpt-6-astra": GPT_6,
1201
+ "gpt-5.6-luna": GPT_5_6,
1202
+ "gpt-5.6-sol": GPT_5_6,
1203
+ "gpt-5.6-terra": GPT_5_6,
1204
+ "gpt-5.5": GPT_5_4,
1205
+ "gpt-5.5-pro": { ...GPT_5_4, off: null, low: null },
1206
+ "gpt-5.4": GPT_5_4,
1207
+ "gpt-5.4-mini": GPT_5_4,
1208
+ "gpt-5.4-nano": GPT_5_4,
1209
+ "gpt-5.4-pro": { ...GPT_5_4, off: null, low: null },
1210
+ "gpt-5.2": GPT_5_4,
1211
+ "gpt-5.1": GPT_5_1,
1212
+ "gpt-5": GPT_5,
1213
+ "gpt-5-mini": GPT_5,
1214
+ "gpt-5-nano": GPT_5,
1215
+ "gpt-5-pro": { off: null, minimal: null, low: null, medium: null, high: "high", xhigh: null, max: null }
1216
+ };
1217
+ var NO_REASONING = /* @__PURE__ */ new Set(["gpt-5-chat-latest", "gpt-5.3-chat-latest"]);
1218
+ function chatModelThinking(id) {
1219
+ if (NO_REASONING.has(id)) {
1220
+ return { reasoning: false, input: ["text", "image"] };
1221
+ }
1222
+ const known = KNOWN[id];
1223
+ if (known) {
1224
+ return { reasoning: true, thinkingLevelMap: known, input: visionInput(id) };
1225
+ }
1226
+ if (/^gpt-6(?:[-.]|$)/iu.test(id)) {
1227
+ return { reasoning: true, thinkingLevelMap: GPT_6, input: ["text", "image"] };
1228
+ }
1229
+ if (/^gpt-5\.6/iu.test(id)) {
1230
+ return { reasoning: true, thinkingLevelMap: GPT_5_6, input: ["text", "image"] };
1231
+ }
1232
+ if (/^gpt-5\.(?:2|3|4|5)/iu.test(id)) {
1233
+ return { reasoning: true, thinkingLevelMap: GPT_5_4, input: ["text", "image"] };
1234
+ }
1235
+ if (/^gpt-5\.1/iu.test(id)) {
1236
+ return { reasoning: true, thinkingLevelMap: GPT_5_1, input: ["text", "image"] };
1237
+ }
1238
+ if (/^gpt-5(?:[-.]|$)/iu.test(id)) {
1239
+ return { reasoning: true, thinkingLevelMap: GPT_5, input: ["text", "image"] };
1240
+ }
1241
+ if (/^(?:o1|o3|o4)(?:[-.]|$)/iu.test(id)) {
1242
+ return { reasoning: true, thinkingLevelMap: O_SERIES, input: ["text"] };
1243
+ }
1244
+ if (/reason/iu.test(id)) {
1245
+ return { reasoning: true, input: ["text"] };
1246
+ }
1247
+ return { reasoning: false, input: ["text"] };
1248
+ }
1249
+ function visionInput(id) {
1250
+ return /^(?:gpt-5|gpt-6)/iu.test(id) ? ["text", "image"] : ["text"];
1251
+ }
1252
+
1105
1253
  // src/discover.ts
1106
1254
  async function discoverDaiCatalog(options = {}) {
1107
1255
  const origin = normalizeOrigin(options.origin ?? DEFAULT_BASE_URL2);
@@ -1188,12 +1336,14 @@ function toChatModel(id, model) {
1188
1336
  const path = model.integration_docs?.path ?? "";
1189
1337
  const responses = path.includes("/responses");
1190
1338
  const rate = model.token_rate;
1339
+ const thinking = chatModelThinking(id);
1191
1340
  return {
1192
1341
  id,
1193
1342
  name: model.display_name?.trim() || id,
1194
1343
  api: responses ? "openai-responses" : "openai-completions",
1195
- reasoning: /gpt-5|o1|o3|o4|reason/iu.test(id),
1196
- input: ["text"],
1344
+ reasoning: thinking.reasoning,
1345
+ ...thinking.thinkingLevelMap === void 0 ? {} : { thinkingLevelMap: thinking.thinkingLevelMap },
1346
+ input: thinking.input,
1197
1347
  cost: {
1198
1348
  input: rate?.input_usd_per_1m_tokens ?? 0,
1199
1349
  output: rate?.output_usd_per_1m_tokens ?? 0,
@@ -1528,7 +1678,7 @@ function registerDaiProvider(pi) {
1528
1678
  return [];
1529
1679
  }
1530
1680
  const file = await loadFileConfig();
1531
- const key = file.apiKey ?? process.env.DAI_API_KEY;
1681
+ const key = file.apiKey ?? process.env.DAI_API_KEY ?? await loadAuthJsonKey();
1532
1682
  const origin = normalizeOrigin(file.baseUrl ?? DEFAULT_BASE_URL2);
1533
1683
  const catalog = await discoverDaiCatalog({
1534
1684
  origin,
@@ -1565,6 +1715,7 @@ function toProviderModels(models, baseUrl) {
1565
1715
  api: model.api,
1566
1716
  baseUrl,
1567
1717
  reasoning: model.reasoning,
1718
+ ...model.thinkingLevelMap === void 0 ? {} : { thinkingLevelMap: model.thinkingLevelMap },
1568
1719
  input: model.input,
1569
1720
  cost: model.cost,
1570
1721
  contextWindow: model.contextWindow,
@@ -1822,7 +1973,7 @@ ${urls}` }],
1822
1973
  return;
1823
1974
  }
1824
1975
  const file = await loadFileConfig();
1825
- const ready = hasApiKey(file);
1976
+ const ready = await hasApiKey(file);
1826
1977
  const models = [
1827
1978
  `image ${DEFAULT_IMAGE_MODEL}`,
1828
1979
  `video ${DEFAULT_VIDEO_MODEL}`,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@d-ai/pi",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "description": "Pi extension for D.AI image, video, and music generation",
5
5
  "license": "MIT",
6
6
  "type": "module",