abelworkflow 1.1.2 → 1.1.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/lib/providers/pi.mjs +91 -32
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -63,7 +63,7 @@ node .\bin\abelworkflow.mjs install --agents-dir "$HOME\.agents"
|
|
|
63
63
|
|
|
64
64
|
- Claude 配置默认写入 `bypassPermissions` 全权限模式(YOLO),第三方 API 仅使用 API Key 认证,不添加任何 MCP 权限。已有 permissions、deny、hooks 和 timeout 保持不变。
|
|
65
65
|
- Codex 只更新 AbelWorkflow 管理的认证字段,保留未知字段、其他 Provider 和用户 token。
|
|
66
|
-
- Pi 0.80.0 及以上版本按无会话启动时实际选中的当前有效 Provider 配置 API
|
|
66
|
+
- Pi 0.80.0 及以上版本按无会话启动时实际选中的当前有效 Provider 配置 API;首次使用且 Pi 明确没有可用模型时,引导创建 `gpt` 自定义 Provider。API Key 保存在 `~/.pi/agent/auth.json`,`models.json` 只保留模型定义;旧 models-only key 会按先写 auth、后删除旧 key 的顺序迁移。
|
|
67
67
|
- Grok 默认模型统一为 `grok-4.20-non-reasoning`。
|
|
68
68
|
- Context7 使用显式 CommonJS 入口 `context7-api.cjs`。
|
|
69
69
|
- dev-browser 发布运行时使用 Node ESM 编译产物,入口为 `node dist/scripts/start.js`,不依赖 Bun 或运行时 `npx tsx`。
|
package/lib/providers/pi.mjs
CHANGED
|
@@ -11,6 +11,10 @@ import {
|
|
|
11
11
|
import { defaultPaths, maskSecret, pathToLabel } from "../paths.mjs";
|
|
12
12
|
|
|
13
13
|
const minimumPiVersion = [0, 80, 0];
|
|
14
|
+
const piBootstrapProviderId = "gpt";
|
|
15
|
+
const piBootstrapApi = "openai-completions";
|
|
16
|
+
const piBootstrapBaseUrl = "https://api.openai.com/v1";
|
|
17
|
+
const piBootstrapModelId = "gpt-5.5";
|
|
14
18
|
const piRpcRequestId = "abelworkflow-provider";
|
|
15
19
|
const piRpcArgs = [
|
|
16
20
|
"--mode", "rpc",
|
|
@@ -68,15 +72,28 @@ function assertSupportedPiVersion(value) {
|
|
|
68
72
|
return version;
|
|
69
73
|
}
|
|
70
74
|
|
|
75
|
+
function getPiProcessInvocation(args, {
|
|
76
|
+
platform = process.platform,
|
|
77
|
+
comspec = process.env.ComSpec || process.env.COMSPEC || "cmd.exe"
|
|
78
|
+
} = {}) {
|
|
79
|
+
return platform === "win32"
|
|
80
|
+
? { command: comspec, args: ["/d", "/c", "pi", ...args] }
|
|
81
|
+
: { command: "pi", args };
|
|
82
|
+
}
|
|
83
|
+
|
|
71
84
|
function detectPiVersion() {
|
|
72
|
-
const
|
|
85
|
+
const invocation = getPiProcessInvocation(["--version"]);
|
|
86
|
+
const result = spawnSync(invocation.command, invocation.args, {
|
|
73
87
|
encoding: "utf8",
|
|
74
|
-
shell: process.platform === "win32",
|
|
75
88
|
stdio: ["ignore", "pipe", "pipe"]
|
|
76
89
|
});
|
|
77
90
|
return result.status === 0 ? `${result.stdout || ""} ${result.stderr || ""}`.trim() : undefined;
|
|
78
91
|
}
|
|
79
92
|
|
|
93
|
+
function isPiUnknownModel(model) {
|
|
94
|
+
return model?.provider === "unknown" && model?.id === "unknown" && model?.api === "unknown";
|
|
95
|
+
}
|
|
96
|
+
|
|
80
97
|
function parsePiRpcEffectiveModel(value) {
|
|
81
98
|
for (const line of String(value || "").split(/\r?\n/u)) {
|
|
82
99
|
let payload;
|
|
@@ -85,27 +102,26 @@ function parsePiRpcEffectiveModel(value) {
|
|
|
85
102
|
} catch {
|
|
86
103
|
continue;
|
|
87
104
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
id,
|
|
99
|
-
api: typeof model.api === "string" ? model.api.trim() : "",
|
|
100
|
-
baseUrl: typeof model.baseUrl === "string" ? model.baseUrl.trim() : ""
|
|
105
|
+
if (payload?.type !== "response"
|
|
106
|
+
|| payload.command !== "get_state"
|
|
107
|
+
|| payload.success !== true) continue;
|
|
108
|
+
const model = payload.data?.model;
|
|
109
|
+
if (model === null) return null;
|
|
110
|
+
const effectiveModel = {
|
|
111
|
+
provider: typeof model?.provider === "string" ? model.provider.trim() : "",
|
|
112
|
+
id: typeof model?.id === "string" ? model.id.trim() : "",
|
|
113
|
+
api: typeof model?.api === "string" ? model.api.trim() : "",
|
|
114
|
+
baseUrl: typeof model?.baseUrl === "string" ? model.baseUrl.trim() : ""
|
|
101
115
|
};
|
|
116
|
+
if (isPiUnknownModel(effectiveModel)) return null;
|
|
117
|
+
if (effectiveModel.provider && effectiveModel.id) return effectiveModel;
|
|
102
118
|
}
|
|
103
119
|
}
|
|
104
120
|
|
|
105
121
|
function runPiRpcCommand(command, args, {
|
|
106
122
|
input = "",
|
|
107
123
|
maxBuffer = 1024 * 1024,
|
|
108
|
-
|
|
124
|
+
platform = process.platform,
|
|
109
125
|
start = spawn,
|
|
110
126
|
timeout = 20000
|
|
111
127
|
} = {}) {
|
|
@@ -129,9 +145,11 @@ function runPiRpcCommand(command, args, {
|
|
|
129
145
|
try {
|
|
130
146
|
const env = { ...process.env };
|
|
131
147
|
delete env.NODE_TEST_CONTEXT;
|
|
132
|
-
|
|
148
|
+
const invocation = command === "pi"
|
|
149
|
+
? getPiProcessInvocation(args, { platform })
|
|
150
|
+
: { command, args };
|
|
151
|
+
child = start(invocation.command, invocation.args, {
|
|
133
152
|
env,
|
|
134
|
-
shell,
|
|
135
153
|
stdio: ["pipe", "pipe", "ignore"],
|
|
136
154
|
windowsHide: true
|
|
137
155
|
});
|
|
@@ -148,7 +166,7 @@ function runPiRpcCommand(command, args, {
|
|
|
148
166
|
stdout += chunk;
|
|
149
167
|
if (Buffer.byteLength(stdout, "utf8") > maxBuffer) {
|
|
150
168
|
finish(null);
|
|
151
|
-
} else if (parsePiRpcEffectiveModel(stdout)) {
|
|
169
|
+
} else if (parsePiRpcEffectiveModel(stdout) !== undefined) {
|
|
152
170
|
finish(0);
|
|
153
171
|
}
|
|
154
172
|
});
|
|
@@ -166,7 +184,7 @@ async function detectPiEffectiveModel(run = runPiRpcCommand) {
|
|
|
166
184
|
encoding: "utf8",
|
|
167
185
|
input: `${JSON.stringify({ id: piRpcRequestId, type: "get_state" })}\n`,
|
|
168
186
|
maxBuffer: 1024 * 1024,
|
|
169
|
-
|
|
187
|
+
platform: process.platform,
|
|
170
188
|
timeout: 20000
|
|
171
189
|
});
|
|
172
190
|
} catch {
|
|
@@ -281,6 +299,37 @@ function resolveExistingPiApiConfig(modelsConfig = {}, settings = {}, auth = {},
|
|
|
281
299
|
};
|
|
282
300
|
}
|
|
283
301
|
|
|
302
|
+
function resolvePiApiTarget(modelsConfig = {}, settings = {}, auth = {}, effectiveModel) {
|
|
303
|
+
const hasNoEffectiveModel = effectiveModel === null || isPiUnknownModel(effectiveModel);
|
|
304
|
+
const configuration = resolveExistingPiApiConfig(
|
|
305
|
+
modelsConfig,
|
|
306
|
+
settings,
|
|
307
|
+
auth,
|
|
308
|
+
hasNoEffectiveModel ? undefined : effectiveModel
|
|
309
|
+
);
|
|
310
|
+
if (configuration.providerId || !hasNoEffectiveModel) {
|
|
311
|
+
return { bootstrap: false, configuration };
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
const provider = modelsConfig.providers?.[piBootstrapProviderId];
|
|
315
|
+
const models = Array.isArray(provider?.models) ? provider.models.filter((model) => model?.id) : [];
|
|
316
|
+
const credential = auth[piBootstrapProviderId];
|
|
317
|
+
const apiKey = credential?.type === "api_key" && typeof credential.key === "string"
|
|
318
|
+
? credential.key
|
|
319
|
+
: typeof provider?.apiKey === "string" ? provider.apiKey : "";
|
|
320
|
+
return {
|
|
321
|
+
bootstrap: true,
|
|
322
|
+
configuration: {
|
|
323
|
+
providerId: piBootstrapProviderId,
|
|
324
|
+
baseUrl: typeof provider?.baseUrl === "string" ? provider.baseUrl : piBootstrapBaseUrl,
|
|
325
|
+
api: typeof provider?.api === "string" ? provider.api : piBootstrapApi,
|
|
326
|
+
apiKey,
|
|
327
|
+
modelIds: models.map((model) => model.id),
|
|
328
|
+
defaultModel: models[0]?.id || piBootstrapModelId
|
|
329
|
+
}
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
|
|
284
333
|
function assertConfigurablePiProvider(modelsConfig = {}, configuration = {}) {
|
|
285
334
|
const { providerId, defaultModel, api } = configuration;
|
|
286
335
|
const provider = modelsConfig.providers?.[providerId];
|
|
@@ -419,11 +468,14 @@ async function persistPiConfiguration(paths, configuration, operations = {}) {
|
|
|
419
468
|
}
|
|
420
469
|
|
|
421
470
|
async function configurePiApi(paths = defaultPaths, ensurePiResourcesLinked = async () => {}, promptApi, runtime = {}) {
|
|
471
|
+
const log = runtime.log ?? p.log;
|
|
472
|
+
const spinner = runtime.spinner ?? p.spinner;
|
|
473
|
+
const text = runtime.text ?? p.text;
|
|
422
474
|
const piVersion = await (runtime.getPiVersion ?? detectPiVersion)();
|
|
423
475
|
try {
|
|
424
476
|
assertSupportedPiVersion(piVersion);
|
|
425
477
|
} catch (error) {
|
|
426
|
-
|
|
478
|
+
log.warn(error.message || String(error));
|
|
427
479
|
return;
|
|
428
480
|
}
|
|
429
481
|
const {
|
|
@@ -437,7 +489,7 @@ async function configurePiApi(paths = defaultPaths, ensurePiResourcesLinked = as
|
|
|
437
489
|
models: modelsConfig,
|
|
438
490
|
settings
|
|
439
491
|
} = await readExistingPiConfiguration(paths);
|
|
440
|
-
const detectionSpinner =
|
|
492
|
+
const detectionSpinner = spinner();
|
|
441
493
|
detectionSpinner.start("正在识别 Pi 当前有效模型");
|
|
442
494
|
let effectiveModel;
|
|
443
495
|
try {
|
|
@@ -447,16 +499,21 @@ async function configurePiApi(paths = defaultPaths, ensurePiResourcesLinked = as
|
|
|
447
499
|
? `已识别 ${effectiveModel.provider}/${effectiveModel.id}`
|
|
448
500
|
: "未识别到 Pi 当前有效模型");
|
|
449
501
|
}
|
|
450
|
-
const
|
|
502
|
+
const target = resolvePiApiTarget(modelsConfig, settings, auth, effectiveModel);
|
|
503
|
+
const existing = target.configuration;
|
|
451
504
|
const providerId = requirePiProviderId(existing.providerId);
|
|
452
|
-
|
|
505
|
+
if (target.bootstrap) {
|
|
506
|
+
log.info(`Pi 尚未配置可用模型,将创建自定义 Provider ${providerId}。`);
|
|
507
|
+
} else {
|
|
508
|
+
assertConfigurablePiProvider(modelsConfig, existing);
|
|
509
|
+
}
|
|
453
510
|
if (effectiveModel
|
|
454
511
|
&& (settings.defaultProvider !== existing.providerId || settings.defaultModel !== existing.defaultModel)) {
|
|
455
|
-
|
|
512
|
+
log.warn(`Pi 保存的默认模型 ${settings.defaultProvider || "未知"}/${settings.defaultModel || "未知"} 与当前有效模型 ${existing.providerId}/${existing.defaultModel} 不同;将配置当前有效模型。`);
|
|
456
513
|
}
|
|
457
514
|
const providerLabel = `Pi ${providerId}`;
|
|
458
515
|
|
|
459
|
-
const baseUrlInput = await
|
|
516
|
+
const baseUrlInput = await text({
|
|
460
517
|
message: `${providerLabel} Base URL`,
|
|
461
518
|
initialValue: existing.baseUrl,
|
|
462
519
|
validate: required()
|
|
@@ -480,7 +537,7 @@ async function configurePiApi(paths = defaultPaths, ensurePiResourcesLinked = as
|
|
|
480
537
|
existingValue: existing.apiKey
|
|
481
538
|
});
|
|
482
539
|
|
|
483
|
-
const modelIdsText = await
|
|
540
|
+
const modelIdsText = await text({
|
|
484
541
|
message: `${providerLabel} 模型 ID(多个用逗号分隔)`,
|
|
485
542
|
initialValue: (existing.modelIds.length
|
|
486
543
|
? existing.modelIds
|
|
@@ -490,7 +547,7 @@ async function configurePiApi(paths = defaultPaths, ensurePiResourcesLinked = as
|
|
|
490
547
|
assertNotCancelled(modelIdsText);
|
|
491
548
|
const modelIds = parsePiModelIds(modelIdsText);
|
|
492
549
|
|
|
493
|
-
const defaultModel = await
|
|
550
|
+
const defaultModel = await text({
|
|
494
551
|
message: "Pi 默认模型",
|
|
495
552
|
initialValue: modelIds.includes(existing.defaultModel) ? existing.defaultModel : modelIds[0],
|
|
496
553
|
validate: (value) => modelIds.includes(String(value || "").trim()) ? undefined : "默认模型必须在模型 ID 列表中"
|
|
@@ -509,10 +566,10 @@ async function configurePiApi(paths = defaultPaths, ensurePiResourcesLinked = as
|
|
|
509
566
|
await ensurePiResourcesLinked(paths);
|
|
510
567
|
await persistPiConfiguration(paths, configuration);
|
|
511
568
|
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
569
|
+
log.step(`已更新 ${pathToLabel(paths.piModelsPath, paths.homeDir)} (${providerId}, ${baseUrl})`);
|
|
570
|
+
log.step(`已更新 ${pathToLabel(paths.piSettingsPath, paths.homeDir)} (默认模型: ${finalDefaultModel})`);
|
|
571
|
+
log.step(`已更新 ${pathToLabel(paths.piAuthPath, paths.homeDir)} (${maskSecret(finalApiKey)})`);
|
|
572
|
+
log.step(`已链接 Pi 扩展到 ${pathToLabel(join(paths.piAgentDir, "extensions"), paths.homeDir)}`);
|
|
516
573
|
}
|
|
517
574
|
|
|
518
575
|
export {
|
|
@@ -525,6 +582,7 @@ export {
|
|
|
525
582
|
configurePiApi,
|
|
526
583
|
detectPiEffectiveModel,
|
|
527
584
|
getPiApiPromptOptions,
|
|
585
|
+
getPiProcessInvocation,
|
|
528
586
|
inferPiApiFromBaseUrl,
|
|
529
587
|
normalizeOpenAiBaseUrl,
|
|
530
588
|
parsePiRpcEffectiveModel,
|
|
@@ -532,6 +590,7 @@ export {
|
|
|
532
590
|
persistPiConfiguration,
|
|
533
591
|
readExistingPiConfiguration,
|
|
534
592
|
resolveExistingPiApiConfig,
|
|
593
|
+
resolvePiApiTarget,
|
|
535
594
|
runPiRpcCommand,
|
|
536
595
|
updatePiAuthFile
|
|
537
596
|
};
|