@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.
- package/README.md +1 -1
- package/dist/index.js +159 -8
- 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
|
|
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
|
-
|
|
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:
|
|
1196
|
-
|
|
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}`,
|