larkin 0.4.27 → 0.4.29
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/dist/app/agent-cli.mjs +4 -2
- package/dist/app/agent-config.mjs +45 -29
- package/dist/app/cli.mjs +16 -6
- package/dist/app/local-control.mjs +16 -3
- package/dist/app/pi-auth-cli.mjs +227 -17
- package/dist/app/runtime-model-directory.mjs +3 -2
- package/dist/app/runtime-process.mjs +42 -5
- package/dist/app/setup.mjs +15 -14
- package/dist/dashboard/dashboard-config-controller.mjs +145 -13
- package/dist/dashboard/dashboard-view-model.mjs +3 -2
- package/dist/dashboard/web/assets/dashboard.css +1 -1
- package/dist/dashboard/web/assets/dashboard.js +15 -15
- package/dist/feishu/host-shell.cjs +68 -16
- package/dist/feishu/host-shell.mjs +69 -17
- package/dist/platform/config.cjs +67 -16
- package/dist/platform/config.mjs +57 -16
- package/dist/runtime/pi-official-auth.cjs +594 -0
- package/dist/runtime/pi-official-auth.mjs +53 -0
- package/dist/runtime/pi-provider-config.cjs +26 -3
- package/dist/runtime/pi-provider-config.mjs +22 -2
- package/dist/runtime/pi-provider-login.mjs +240 -0
- package/dist/runtime/runtime-adapters.mjs +24 -4
- package/dist/runtime/runtime-host.cjs +215 -16
- package/dist/runtime/runtime-host.mjs +216 -17
- package/dist/runtime/runtime-model-catalog.cjs +4 -3
- package/dist/runtime/runtime-model-catalog.mjs +4 -3
- package/dist/runtime/runtime-readiness.cjs +123 -3
- package/dist/runtime/runtime-readiness.mjs +116 -4
- package/dist/runtime/user-runtime.cjs +51 -0
- package/dist/runtime/user-runtime.mjs +41 -0
- package/dist/setup/bot-register.mjs +3 -3
- package/dist/setup/setup-agent-choice.mjs +10 -9
- package/dist/setup/setup-bind.mjs +2 -2
- package/package.json +1 -1
|
@@ -208,26 +208,72 @@ function createHostShell({ env = process.env, runtimeHost, channelPackage, event
|
|
|
208
208
|
runtimeReadiness: { runtime: agent.runtime, state: "unavailable", reason, nextAction: "Wait for the current daemon epoch to publish Runtime readiness.", observedAt: new Date().toISOString() },
|
|
209
209
|
});
|
|
210
210
|
};
|
|
211
|
+
const unresolvedCurrentAuth = (agent) => {
|
|
212
|
+
try {
|
|
213
|
+
const persisted = (0, runtime_readiness_js_1.parsePersistedAuthFailure)(stateStore(agent).readJson("agentState", {}));
|
|
214
|
+
if (!persisted)
|
|
215
|
+
return null;
|
|
216
|
+
// 只使用当前 agentState 作用域标记,不扫描历史 delivery 的 authProvider。
|
|
217
|
+
return (0, runtime_readiness_js_1.authFailureAppliesTo)({
|
|
218
|
+
runtime: agent.runtime,
|
|
219
|
+
model: agent.model,
|
|
220
|
+
piDistribution: agent.piDistribution,
|
|
221
|
+
}, persisted) ? persisted : null;
|
|
222
|
+
}
|
|
223
|
+
catch {
|
|
224
|
+
return null;
|
|
225
|
+
}
|
|
226
|
+
};
|
|
227
|
+
const projectReadyUnlessUnresolvedAuth = (agent, observedAt) => {
|
|
228
|
+
const failure = unresolvedCurrentAuth(agent);
|
|
229
|
+
if (failure) {
|
|
230
|
+
hostState.updateStatus(agent, {
|
|
231
|
+
runtimeReadiness: { ...(0, runtime_readiness_js_1.readinessForPersistedAuthFailure)(failure), observedAt },
|
|
232
|
+
});
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
hostState.updateStatus(agent, { runtimeReadiness: { runtime: agent.runtime, state: "ready", observedAt } });
|
|
236
|
+
};
|
|
211
237
|
const recordInboundDeliveryFailure = (agent, code) => {
|
|
212
238
|
const at = new Date().toISOString();
|
|
213
239
|
const reason = "Inbound Runtime delivery failed non-retryably; durable Inbox/ledger state is retained for recovery.";
|
|
214
240
|
const nextAction = "Inspect the delivery/status error, correct the Runtime or canonical Inbox state, then restart to replay safely.";
|
|
241
|
+
const currentReadiness = hostState.readStatus(agent).runtimeReadiness;
|
|
215
242
|
hostState.updateStatus(agent, {
|
|
216
243
|
inboundDeliveryHealth: { state: "error", code, at, reason, nextAction },
|
|
217
|
-
|
|
244
|
+
...(currentReadiness?.state === "unauthenticated" ? {} : {
|
|
245
|
+
runtimeReadiness: { runtime: agent.runtime, state: "incompatible", reason, nextAction },
|
|
246
|
+
}),
|
|
218
247
|
});
|
|
219
248
|
hostState.recordStatusError(agent, `${reason} ${nextAction} code=${code}`);
|
|
220
249
|
};
|
|
221
250
|
const agentStates = new Map();
|
|
251
|
+
const mergePersistedAgentState = (record) => {
|
|
252
|
+
const latest = record.store.readJson("agentState", {});
|
|
253
|
+
if (isRecord(latest.previousSessions)) {
|
|
254
|
+
record.state.previousSessions = {
|
|
255
|
+
...latest.previousSessions,
|
|
256
|
+
...(record.state.previousSessions ?? {}),
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
const persisted = (0, runtime_readiness_js_1.parsePersistedAuthFailure)(latest);
|
|
260
|
+
if (persisted) {
|
|
261
|
+
record.state.authFailure = persisted;
|
|
262
|
+
if (persisted.kind === "missing-provider" && persisted.provider) {
|
|
263
|
+
record.state.authFailureProvider = persisted.provider;
|
|
264
|
+
}
|
|
265
|
+
else {
|
|
266
|
+
delete record.state.authFailureProvider;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
else {
|
|
270
|
+
delete record.state.authFailure;
|
|
271
|
+
delete record.state.authFailureProvider;
|
|
272
|
+
}
|
|
273
|
+
};
|
|
222
274
|
const saveAgentState = (record) => {
|
|
223
275
|
try {
|
|
224
|
-
|
|
225
|
-
if (isRecord(latest.previousSessions)) {
|
|
226
|
-
record.state.previousSessions = {
|
|
227
|
-
...latest.previousSessions,
|
|
228
|
-
...(record.state.previousSessions ?? {}),
|
|
229
|
-
};
|
|
230
|
-
}
|
|
276
|
+
mergePersistedAgentState(record);
|
|
231
277
|
record.store.writeJson("agentState", record.state);
|
|
232
278
|
}
|
|
233
279
|
catch (error) {
|
|
@@ -1276,12 +1322,16 @@ function createHostShell({ env = process.env, runtimeHost, channelPackage, event
|
|
|
1276
1322
|
observedAt,
|
|
1277
1323
|
},
|
|
1278
1324
|
});
|
|
1279
|
-
else if (message.readiness)
|
|
1280
|
-
|
|
1325
|
+
else if (message.readiness) {
|
|
1326
|
+
if (message.readiness.state === "ready" && unresolvedCurrentAuth(agent)) {
|
|
1327
|
+
projectReadyUnlessUnresolvedAuth(agent, observedAt);
|
|
1328
|
+
}
|
|
1329
|
+
else {
|
|
1330
|
+
hostState.updateStatus(agent, { runtimeReadiness: { ...message.readiness, observedAt } });
|
|
1331
|
+
}
|
|
1332
|
+
}
|
|
1281
1333
|
else if (message.status === "active")
|
|
1282
|
-
|
|
1283
|
-
runtime: agent.runtime, state: "ready", observedAt,
|
|
1284
|
-
} });
|
|
1334
|
+
projectReadyUnlessUnresolvedAuth(agent, observedAt);
|
|
1285
1335
|
if (message.status === "active") {
|
|
1286
1336
|
const redeliveryTimer = setTimeout(() => {
|
|
1287
1337
|
void reminder.redeliverUnread(agent).catch((error) => log("启动补投失败", errorMessage(error)));
|
|
@@ -1448,6 +1498,7 @@ function createHostShell({ env = process.env, runtimeHost, channelPackage, event
|
|
|
1448
1498
|
record.state.sessions[agent.runtime] = reset.sessionId;
|
|
1449
1499
|
else
|
|
1450
1500
|
delete record.state.sessions[agent.runtime];
|
|
1501
|
+
mergePersistedAgentState(record);
|
|
1451
1502
|
record.store.writeJson("agentState", record.state);
|
|
1452
1503
|
}
|
|
1453
1504
|
if (!reset.sessionId) {
|
|
@@ -1455,11 +1506,11 @@ function createHostShell({ env = process.env, runtimeHost, channelPackage, event
|
|
|
1455
1506
|
hostState.updateStatus(agent, {
|
|
1456
1507
|
session: { runtime: agent.runtime, id: null, launchId: null, startedAt: observedAt,
|
|
1457
1508
|
lastSeenAt: null, lastTurnAt: null, turns: 0 },
|
|
1458
|
-
runtimeReadiness: { runtime: agent.runtime, state: "ready", observedAt },
|
|
1459
1509
|
});
|
|
1510
|
+
projectReadyUnlessUnresolvedAuth(agent, observedAt);
|
|
1460
1511
|
}
|
|
1461
1512
|
else if (reset.runtimeReady) {
|
|
1462
|
-
|
|
1513
|
+
projectReadyUnlessUnresolvedAuth(agent, new Date().toISOString());
|
|
1463
1514
|
}
|
|
1464
1515
|
}
|
|
1465
1516
|
catch (error) {
|
|
@@ -1527,7 +1578,7 @@ function createHostShell({ env = process.env, runtimeHost, channelPackage, event
|
|
|
1527
1578
|
throw Object.assign(error instanceof Error ? error : new Error(String(error)), readinessProjection());
|
|
1528
1579
|
}
|
|
1529
1580
|
if (recovery.runtimeReady) {
|
|
1530
|
-
|
|
1581
|
+
projectReadyUnlessUnresolvedAuth(agent, new Date().toISOString());
|
|
1531
1582
|
}
|
|
1532
1583
|
const record = agentStates.get(agentId);
|
|
1533
1584
|
try {
|
|
@@ -1536,6 +1587,7 @@ function createHostShell({ env = process.env, runtimeHost, channelPackage, event
|
|
|
1536
1587
|
record.state.sessions[agent.runtime] = recovery.sessionId;
|
|
1537
1588
|
else
|
|
1538
1589
|
delete record.state.sessions[agent.runtime];
|
|
1590
|
+
mergePersistedAgentState(record);
|
|
1539
1591
|
record.store.writeJson("agentState", record.state);
|
|
1540
1592
|
}
|
|
1541
1593
|
}
|
|
@@ -16,7 +16,7 @@ import { inboxAuditRegistryFile, observeInboxAuditTarget } from "../agent/missed
|
|
|
16
16
|
import { HostChannelBusiness } from "./host-channel-business.mjs";
|
|
17
17
|
import { HostInteractionOrchestrator } from "./interaction-orchestrator.mjs";
|
|
18
18
|
import { targetFor } from "./message-policy.mjs";
|
|
19
|
-
import { providerAuthenticationFailureReadiness, RuntimePrerequisiteError } from "../runtime/runtime-readiness.mjs";
|
|
19
|
+
import { authFailureAppliesTo, parsePersistedAuthFailure, providerAuthenticationFailureReadiness, readinessForPersistedAuthFailure, RuntimePrerequisiteError, } from "../runtime/runtime-readiness.mjs";
|
|
20
20
|
import { readDocumentCommentSubscription, verifyCallbackProbe } from "../platform/callback-capability.mjs";
|
|
21
21
|
import { loadConfig, resolveMentionPolicy } from "../platform/config.mjs";
|
|
22
22
|
import { processCommandToken } from "../app/internal-command.mjs";
|
|
@@ -168,26 +168,72 @@ export function createHostShell({ env = process.env, runtimeHost, channelPackage
|
|
|
168
168
|
runtimeReadiness: { runtime: agent.runtime, state: "unavailable", reason, nextAction: "Wait for the current daemon epoch to publish Runtime readiness.", observedAt: new Date().toISOString() },
|
|
169
169
|
});
|
|
170
170
|
};
|
|
171
|
+
const unresolvedCurrentAuth = (agent) => {
|
|
172
|
+
try {
|
|
173
|
+
const persisted = parsePersistedAuthFailure(stateStore(agent).readJson("agentState", {}));
|
|
174
|
+
if (!persisted)
|
|
175
|
+
return null;
|
|
176
|
+
// 只使用当前 agentState 作用域标记,不扫描历史 delivery 的 authProvider。
|
|
177
|
+
return authFailureAppliesTo({
|
|
178
|
+
runtime: agent.runtime,
|
|
179
|
+
model: agent.model,
|
|
180
|
+
piDistribution: agent.piDistribution,
|
|
181
|
+
}, persisted) ? persisted : null;
|
|
182
|
+
}
|
|
183
|
+
catch {
|
|
184
|
+
return null;
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
const projectReadyUnlessUnresolvedAuth = (agent, observedAt) => {
|
|
188
|
+
const failure = unresolvedCurrentAuth(agent);
|
|
189
|
+
if (failure) {
|
|
190
|
+
hostState.updateStatus(agent, {
|
|
191
|
+
runtimeReadiness: { ...readinessForPersistedAuthFailure(failure), observedAt },
|
|
192
|
+
});
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
hostState.updateStatus(agent, { runtimeReadiness: { runtime: agent.runtime, state: "ready", observedAt } });
|
|
196
|
+
};
|
|
171
197
|
const recordInboundDeliveryFailure = (agent, code) => {
|
|
172
198
|
const at = new Date().toISOString();
|
|
173
199
|
const reason = "Inbound Runtime delivery failed non-retryably; durable Inbox/ledger state is retained for recovery.";
|
|
174
200
|
const nextAction = "Inspect the delivery/status error, correct the Runtime or canonical Inbox state, then restart to replay safely.";
|
|
201
|
+
const currentReadiness = hostState.readStatus(agent).runtimeReadiness;
|
|
175
202
|
hostState.updateStatus(agent, {
|
|
176
203
|
inboundDeliveryHealth: { state: "error", code, at, reason, nextAction },
|
|
177
|
-
|
|
204
|
+
...(currentReadiness?.state === "unauthenticated" ? {} : {
|
|
205
|
+
runtimeReadiness: { runtime: agent.runtime, state: "incompatible", reason, nextAction },
|
|
206
|
+
}),
|
|
178
207
|
});
|
|
179
208
|
hostState.recordStatusError(agent, `${reason} ${nextAction} code=${code}`);
|
|
180
209
|
};
|
|
181
210
|
const agentStates = new Map();
|
|
211
|
+
const mergePersistedAgentState = (record) => {
|
|
212
|
+
const latest = record.store.readJson("agentState", {});
|
|
213
|
+
if (isRecord(latest.previousSessions)) {
|
|
214
|
+
record.state.previousSessions = {
|
|
215
|
+
...latest.previousSessions,
|
|
216
|
+
...(record.state.previousSessions ?? {}),
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
const persisted = parsePersistedAuthFailure(latest);
|
|
220
|
+
if (persisted) {
|
|
221
|
+
record.state.authFailure = persisted;
|
|
222
|
+
if (persisted.kind === "missing-provider" && persisted.provider) {
|
|
223
|
+
record.state.authFailureProvider = persisted.provider;
|
|
224
|
+
}
|
|
225
|
+
else {
|
|
226
|
+
delete record.state.authFailureProvider;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
else {
|
|
230
|
+
delete record.state.authFailure;
|
|
231
|
+
delete record.state.authFailureProvider;
|
|
232
|
+
}
|
|
233
|
+
};
|
|
182
234
|
const saveAgentState = (record) => {
|
|
183
235
|
try {
|
|
184
|
-
|
|
185
|
-
if (isRecord(latest.previousSessions)) {
|
|
186
|
-
record.state.previousSessions = {
|
|
187
|
-
...latest.previousSessions,
|
|
188
|
-
...(record.state.previousSessions ?? {}),
|
|
189
|
-
};
|
|
190
|
-
}
|
|
236
|
+
mergePersistedAgentState(record);
|
|
191
237
|
record.store.writeJson("agentState", record.state);
|
|
192
238
|
}
|
|
193
239
|
catch (error) {
|
|
@@ -1236,12 +1282,16 @@ export function createHostShell({ env = process.env, runtimeHost, channelPackage
|
|
|
1236
1282
|
observedAt,
|
|
1237
1283
|
},
|
|
1238
1284
|
});
|
|
1239
|
-
else if (message.readiness)
|
|
1240
|
-
|
|
1285
|
+
else if (message.readiness) {
|
|
1286
|
+
if (message.readiness.state === "ready" && unresolvedCurrentAuth(agent)) {
|
|
1287
|
+
projectReadyUnlessUnresolvedAuth(agent, observedAt);
|
|
1288
|
+
}
|
|
1289
|
+
else {
|
|
1290
|
+
hostState.updateStatus(agent, { runtimeReadiness: { ...message.readiness, observedAt } });
|
|
1291
|
+
}
|
|
1292
|
+
}
|
|
1241
1293
|
else if (message.status === "active")
|
|
1242
|
-
|
|
1243
|
-
runtime: agent.runtime, state: "ready", observedAt,
|
|
1244
|
-
} });
|
|
1294
|
+
projectReadyUnlessUnresolvedAuth(agent, observedAt);
|
|
1245
1295
|
if (message.status === "active") {
|
|
1246
1296
|
const redeliveryTimer = setTimeout(() => {
|
|
1247
1297
|
void reminder.redeliverUnread(agent).catch((error) => log("启动补投失败", errorMessage(error)));
|
|
@@ -1408,6 +1458,7 @@ export function createHostShell({ env = process.env, runtimeHost, channelPackage
|
|
|
1408
1458
|
record.state.sessions[agent.runtime] = reset.sessionId;
|
|
1409
1459
|
else
|
|
1410
1460
|
delete record.state.sessions[agent.runtime];
|
|
1461
|
+
mergePersistedAgentState(record);
|
|
1411
1462
|
record.store.writeJson("agentState", record.state);
|
|
1412
1463
|
}
|
|
1413
1464
|
if (!reset.sessionId) {
|
|
@@ -1415,11 +1466,11 @@ export function createHostShell({ env = process.env, runtimeHost, channelPackage
|
|
|
1415
1466
|
hostState.updateStatus(agent, {
|
|
1416
1467
|
session: { runtime: agent.runtime, id: null, launchId: null, startedAt: observedAt,
|
|
1417
1468
|
lastSeenAt: null, lastTurnAt: null, turns: 0 },
|
|
1418
|
-
runtimeReadiness: { runtime: agent.runtime, state: "ready", observedAt },
|
|
1419
1469
|
});
|
|
1470
|
+
projectReadyUnlessUnresolvedAuth(agent, observedAt);
|
|
1420
1471
|
}
|
|
1421
1472
|
else if (reset.runtimeReady) {
|
|
1422
|
-
|
|
1473
|
+
projectReadyUnlessUnresolvedAuth(agent, new Date().toISOString());
|
|
1423
1474
|
}
|
|
1424
1475
|
}
|
|
1425
1476
|
catch (error) {
|
|
@@ -1487,7 +1538,7 @@ export function createHostShell({ env = process.env, runtimeHost, channelPackage
|
|
|
1487
1538
|
throw Object.assign(error instanceof Error ? error : new Error(String(error)), readinessProjection());
|
|
1488
1539
|
}
|
|
1489
1540
|
if (recovery.runtimeReady) {
|
|
1490
|
-
|
|
1541
|
+
projectReadyUnlessUnresolvedAuth(agent, new Date().toISOString());
|
|
1491
1542
|
}
|
|
1492
1543
|
const record = agentStates.get(agentId);
|
|
1493
1544
|
try {
|
|
@@ -1496,6 +1547,7 @@ export function createHostShell({ env = process.env, runtimeHost, channelPackage
|
|
|
1496
1547
|
record.state.sessions[agent.runtime] = recovery.sessionId;
|
|
1497
1548
|
else
|
|
1498
1549
|
delete record.state.sessions[agent.runtime];
|
|
1550
|
+
mergePersistedAgentState(record);
|
|
1499
1551
|
record.store.writeJson("agentState", record.state);
|
|
1500
1552
|
}
|
|
1501
1553
|
}
|
package/dist/platform/config.cjs
CHANGED
|
@@ -36,6 +36,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
36
36
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
37
|
};
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.toUserRuntime = exports.runtimeOptionTarget = exports.runtimeOptionOf = exports.isUserRuntime = exports.isAdapterRuntime = exports.fromUserRuntime = exports.RUNTIME_OPTIONS = void 0;
|
|
39
40
|
exports.loadRuntimeModels = loadRuntimeModels;
|
|
40
41
|
exports.defaultModelFor = defaultModelFor;
|
|
41
42
|
exports.resolveConfigDir = resolveConfigDir;
|
|
@@ -52,6 +53,8 @@ exports.resolveAgentGlobalMentionPolicy = resolveAgentGlobalMentionPolicy;
|
|
|
52
53
|
exports.runtimeConfigSignature = runtimeConfigSignature;
|
|
53
54
|
exports.configApplyState = configApplyState;
|
|
54
55
|
exports.markConfigApplied = markConfigApplied;
|
|
56
|
+
exports.withConfigMutationLock = withConfigMutationLock;
|
|
57
|
+
exports.withConfigMutationLockAsync = withConfigMutationLockAsync;
|
|
55
58
|
exports.mutateConfig = mutateConfig;
|
|
56
59
|
exports.rollbackConfig = rollbackConfig;
|
|
57
60
|
exports.commitSetupConfig = commitSetupConfig;
|
|
@@ -63,8 +66,18 @@ const path = __importStar(require("node:path"));
|
|
|
63
66
|
const root_layout_js_1 = require("./root-layout.cjs");
|
|
64
67
|
const secure_metadata_js_1 = require("./secure-metadata.cjs");
|
|
65
68
|
const runtime_model_catalog_js_1 = require("../runtime/runtime-model-catalog.cjs");
|
|
69
|
+
const pi_provider_config_js_1 = require("../runtime/pi-provider-config.cjs");
|
|
70
|
+
const user_runtime_js_1 = require("../runtime/user-runtime.cjs");
|
|
66
71
|
const process_inspect_cjs_1 = __importDefault(require("./process-inspect.cjs"));
|
|
67
72
|
const pi_profile_migration_js_1 = require("../runtime/pi-profile-migration.cjs");
|
|
73
|
+
var user_runtime_js_2 = require("../runtime/user-runtime.cjs");
|
|
74
|
+
Object.defineProperty(exports, "RUNTIME_OPTIONS", { enumerable: true, get: function () { return user_runtime_js_2.RUNTIME_OPTIONS; } });
|
|
75
|
+
Object.defineProperty(exports, "fromUserRuntime", { enumerable: true, get: function () { return user_runtime_js_2.fromUserRuntime; } });
|
|
76
|
+
Object.defineProperty(exports, "isAdapterRuntime", { enumerable: true, get: function () { return user_runtime_js_2.isAdapterRuntime; } });
|
|
77
|
+
Object.defineProperty(exports, "isUserRuntime", { enumerable: true, get: function () { return user_runtime_js_2.isUserRuntime; } });
|
|
78
|
+
Object.defineProperty(exports, "runtimeOptionOf", { enumerable: true, get: function () { return user_runtime_js_2.runtimeOptionOf; } });
|
|
79
|
+
Object.defineProperty(exports, "runtimeOptionTarget", { enumerable: true, get: function () { return user_runtime_js_2.runtimeOptionTarget; } });
|
|
80
|
+
Object.defineProperty(exports, "toUserRuntime", { enumerable: true, get: function () { return user_runtime_js_2.toUserRuntime; } });
|
|
68
81
|
const TOP_FIELDS_V3 = new Set(["version", "serverId", "activeAgent", "agents"]);
|
|
69
82
|
const TOP_FIELDS_V4 = new Set(["version", "serverId", "mentionPolicy", "activeAgent", "agents"]);
|
|
70
83
|
const AGENT_FIELDS_V3 = new Set(["runtime", "model", "effort", "noMentionChats", "createdAt"]);
|
|
@@ -105,7 +118,8 @@ function loadRuntimeModels() {
|
|
|
105
118
|
return runtimeModels;
|
|
106
119
|
}
|
|
107
120
|
function defaultModelFor(runtime) {
|
|
108
|
-
const
|
|
121
|
+
const adapter = (0, user_runtime_js_1.isUserRuntime)(runtime) ? (0, user_runtime_js_1.fromUserRuntime)(runtime).runtime : runtime;
|
|
122
|
+
const models = loadRuntimeModels()[adapter];
|
|
109
123
|
if (!models)
|
|
110
124
|
throw new Error(`runtime 模型目录不存在 runtime: ${runtime}`);
|
|
111
125
|
return models[0].id;
|
|
@@ -153,7 +167,7 @@ function validateStoredAgent(key, agent, version) {
|
|
|
153
167
|
assertAllowedFields(agent, version === 3 ? AGENT_FIELDS_V3 : AGENT_FIELDS_V4, `Agent ${key}`);
|
|
154
168
|
if (typeof agent.runtime !== "string" || !agent.runtime)
|
|
155
169
|
throw new Error(`Agent ${key}.runtime 必须是非空字符串`);
|
|
156
|
-
if (!
|
|
170
|
+
if (!(0, user_runtime_js_1.isAdapterRuntime)(agent.runtime))
|
|
157
171
|
throw new Error(`Agent ${key}.runtime 未知:${agent.runtime}`);
|
|
158
172
|
if (typeof agent.model !== "string" || !agent.model)
|
|
159
173
|
throw new Error(`Agent ${key}.model 必须是非空字符串`);
|
|
@@ -632,16 +646,30 @@ function applyMutation(config, mutation) {
|
|
|
632
646
|
agent.piDistribution = mutation.distribution;
|
|
633
647
|
}
|
|
634
648
|
else if (mutation.kind === "set-agent-runtime") {
|
|
635
|
-
if (!
|
|
649
|
+
if (!(0, user_runtime_js_1.isUserRuntime)(mutation.runtime))
|
|
636
650
|
throw new Error(`未知 runtime:${mutation.runtime}`);
|
|
637
|
-
|
|
638
|
-
|
|
651
|
+
const stored = (0, user_runtime_js_1.fromUserRuntime)(mutation.runtime);
|
|
652
|
+
if (stored.piDistribution === "builtin") {
|
|
653
|
+
try {
|
|
654
|
+
(0, pi_provider_config_js_1.assertBuiltinPiAgentDirectory)((0, pi_provider_config_js_1.piAgentDirectory)(config.configDir, mutation.agentId));
|
|
655
|
+
}
|
|
656
|
+
catch (error) {
|
|
657
|
+
throw new Error(`无法切换到 builtin-pi:${error instanceof Error ? error.message : String(error)}。请使用 Dashboard Provider Credentials 或 larkin pi-auth login。`);
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
assertModel(stored.runtime, mutation.model || "default");
|
|
661
|
+
agent.runtime = stored.runtime;
|
|
639
662
|
agent.model = mutation.model || "default";
|
|
640
|
-
if (
|
|
663
|
+
if (stored.piDistribution)
|
|
664
|
+
agent.piDistribution = stored.piDistribution;
|
|
665
|
+
else
|
|
641
666
|
delete agent.piDistribution;
|
|
642
667
|
delete agent.effort;
|
|
643
668
|
}
|
|
644
669
|
else if (mutation.kind === "set-agent-model") {
|
|
670
|
+
if (mutation.requireBuiltinPi && (agent.runtime !== "pi" || agent.piDistribution !== "builtin")) {
|
|
671
|
+
throw new Error(`Agent ${mutation.agentId} 不是内置 Pi`);
|
|
672
|
+
}
|
|
645
673
|
if (!mutation.model.trim())
|
|
646
674
|
throw new Error("model 不能为空");
|
|
647
675
|
assertModel(agent.runtime, mutation.model);
|
|
@@ -792,7 +820,7 @@ function assertConfigRoot(root) {
|
|
|
792
820
|
if (typeof process.getuid === "function" && stat.uid !== process.getuid())
|
|
793
821
|
throw new Error("config root owner is unsafe");
|
|
794
822
|
}
|
|
795
|
-
function
|
|
823
|
+
function acquireConfigLock(layout) {
|
|
796
824
|
assertNoSymlinkAncestors(layout.root);
|
|
797
825
|
fs.mkdirSync(layout.root, { recursive: true, mode: 0o700 });
|
|
798
826
|
const rootStat = fs.lstatSync(layout.root);
|
|
@@ -831,20 +859,43 @@ function withConfigLock(layout, action) {
|
|
|
831
859
|
}
|
|
832
860
|
if (!acquired)
|
|
833
861
|
throw new Error("配置正被其他进程修改,请稍后重试");
|
|
862
|
+
return {
|
|
863
|
+
release() {
|
|
864
|
+
const current = readLockRecord(lock);
|
|
865
|
+
if (current?.record?.nonce === owner.nonce && current.record.pid === owner.pid) {
|
|
866
|
+
try {
|
|
867
|
+
fs.unlinkSync(lock);
|
|
868
|
+
(0, secure_metadata_js_1.fsyncDirectoryOf)(lock);
|
|
869
|
+
}
|
|
870
|
+
catch { /* best effort */ }
|
|
871
|
+
}
|
|
872
|
+
},
|
|
873
|
+
};
|
|
874
|
+
}
|
|
875
|
+
function withConfigLock(layout, action) {
|
|
876
|
+
const held = acquireConfigLock(layout);
|
|
834
877
|
try {
|
|
835
878
|
recoverMigrationJournal(layout.root);
|
|
836
879
|
recoverRollbackJournal(layout.root);
|
|
837
880
|
return action();
|
|
838
881
|
}
|
|
839
882
|
finally {
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
883
|
+
held.release();
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
function withConfigMutationLock(env, action) {
|
|
887
|
+
return withConfigLock(root_layout_js_1.TargetRootLayout.fromConfigDir(resolveConfigDir(env)), action);
|
|
888
|
+
}
|
|
889
|
+
async function withConfigMutationLockAsync(env, action) {
|
|
890
|
+
const layout = root_layout_js_1.TargetRootLayout.fromConfigDir(resolveConfigDir(env));
|
|
891
|
+
const held = acquireConfigLock(layout);
|
|
892
|
+
try {
|
|
893
|
+
recoverMigrationJournal(layout.root);
|
|
894
|
+
recoverRollbackJournal(layout.root);
|
|
895
|
+
return await action();
|
|
896
|
+
}
|
|
897
|
+
finally {
|
|
898
|
+
held.release();
|
|
848
899
|
}
|
|
849
900
|
}
|
|
850
901
|
const CONFIG_ROLLBACK_JOURNAL_FILE = ".config-rollback-journal.json";
|
|
@@ -1105,7 +1156,7 @@ function commitSetupConfig(env, expectedRevision, nextStored) {
|
|
|
1105
1156
|
function safeConfigView(config, onlyAgentId, chatId, applyState) {
|
|
1106
1157
|
const entries = onlyAgentId ? [[onlyAgentId, config.agents[onlyAgentId]]] : Object.entries(config.agents);
|
|
1107
1158
|
const agents = entries.filter((entry) => Boolean(entry[1])).map(([agentId, agent]) => ({
|
|
1108
|
-
agentId, runtime: agent.runtime, model: agent.model, piDistribution: agent.piDistribution ?? (agent.runtime === "pi" ? "external" : null), effort: agent.effort ?? null,
|
|
1159
|
+
agentId, runtime: agent.runtime, runtimeOption: (0, user_runtime_js_1.toUserRuntime)(agent.runtime, agent.piDistribution), model: agent.model, piDistribution: agent.piDistribution ?? (agent.runtime === "pi" ? "external" : null), effort: agent.effort ?? null,
|
|
1109
1160
|
mention: {
|
|
1110
1161
|
override: agent.mentionPolicy ?? "inherit",
|
|
1111
1162
|
effective: agent.mentionPolicy ?? config.mentionPolicy,
|
package/dist/platform/config.mjs
CHANGED
|
@@ -5,8 +5,11 @@ import * as path from "node:path";
|
|
|
5
5
|
import { TargetRootLayout, resolveConfigDir as resolveRootConfigDir } from "./root-layout.mjs";
|
|
6
6
|
import { exactMode, fsyncDirectoryOf } from "./secure-metadata.mjs";
|
|
7
7
|
import { CURRENT_RUNTIME_MODELS } from "../runtime/runtime-model-catalog.mjs";
|
|
8
|
+
import { assertBuiltinPiAgentDirectory, piAgentDirectory } from "../runtime/pi-provider-config.mjs";
|
|
9
|
+
import { fromUserRuntime, isAdapterRuntime, isUserRuntime, toUserRuntime } from "../runtime/user-runtime.mjs";
|
|
8
10
|
import processInspect from "./process-inspect.cjs";
|
|
9
11
|
import { applyPiProfileMigration, assertPiProfileMigrationAfterState, preparePiProfileMigration, releasePiProfileMigrationLock, rollbackPiProfileMigration, validatePiProfileMigrationState, } from "../runtime/pi-profile-migration.mjs";
|
|
12
|
+
export { RUNTIME_OPTIONS, fromUserRuntime, isAdapterRuntime, isUserRuntime, runtimeOptionOf, runtimeOptionTarget, toUserRuntime, } from "../runtime/user-runtime.mjs";
|
|
10
13
|
const TOP_FIELDS_V3 = new Set(["version", "serverId", "activeAgent", "agents"]);
|
|
11
14
|
const TOP_FIELDS_V4 = new Set(["version", "serverId", "mentionPolicy", "activeAgent", "agents"]);
|
|
12
15
|
const AGENT_FIELDS_V3 = new Set(["runtime", "model", "effort", "noMentionChats", "createdAt"]);
|
|
@@ -47,7 +50,8 @@ export function loadRuntimeModels() {
|
|
|
47
50
|
return runtimeModels;
|
|
48
51
|
}
|
|
49
52
|
export function defaultModelFor(runtime) {
|
|
50
|
-
const
|
|
53
|
+
const adapter = isUserRuntime(runtime) ? fromUserRuntime(runtime).runtime : runtime;
|
|
54
|
+
const models = loadRuntimeModels()[adapter];
|
|
51
55
|
if (!models)
|
|
52
56
|
throw new Error(`runtime 模型目录不存在 runtime: ${runtime}`);
|
|
53
57
|
return models[0].id;
|
|
@@ -95,7 +99,7 @@ function validateStoredAgent(key, agent, version) {
|
|
|
95
99
|
assertAllowedFields(agent, version === 3 ? AGENT_FIELDS_V3 : AGENT_FIELDS_V4, `Agent ${key}`);
|
|
96
100
|
if (typeof agent.runtime !== "string" || !agent.runtime)
|
|
97
101
|
throw new Error(`Agent ${key}.runtime 必须是非空字符串`);
|
|
98
|
-
if (!
|
|
102
|
+
if (!isAdapterRuntime(agent.runtime))
|
|
99
103
|
throw new Error(`Agent ${key}.runtime 未知:${agent.runtime}`);
|
|
100
104
|
if (typeof agent.model !== "string" || !agent.model)
|
|
101
105
|
throw new Error(`Agent ${key}.model 必须是非空字符串`);
|
|
@@ -574,16 +578,30 @@ function applyMutation(config, mutation) {
|
|
|
574
578
|
agent.piDistribution = mutation.distribution;
|
|
575
579
|
}
|
|
576
580
|
else if (mutation.kind === "set-agent-runtime") {
|
|
577
|
-
if (!
|
|
581
|
+
if (!isUserRuntime(mutation.runtime))
|
|
578
582
|
throw new Error(`未知 runtime:${mutation.runtime}`);
|
|
579
|
-
|
|
580
|
-
|
|
583
|
+
const stored = fromUserRuntime(mutation.runtime);
|
|
584
|
+
if (stored.piDistribution === "builtin") {
|
|
585
|
+
try {
|
|
586
|
+
assertBuiltinPiAgentDirectory(piAgentDirectory(config.configDir, mutation.agentId));
|
|
587
|
+
}
|
|
588
|
+
catch (error) {
|
|
589
|
+
throw new Error(`无法切换到 builtin-pi:${error instanceof Error ? error.message : String(error)}。请使用 Dashboard Provider Credentials 或 larkin pi-auth login。`);
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
assertModel(stored.runtime, mutation.model || "default");
|
|
593
|
+
agent.runtime = stored.runtime;
|
|
581
594
|
agent.model = mutation.model || "default";
|
|
582
|
-
if (
|
|
595
|
+
if (stored.piDistribution)
|
|
596
|
+
agent.piDistribution = stored.piDistribution;
|
|
597
|
+
else
|
|
583
598
|
delete agent.piDistribution;
|
|
584
599
|
delete agent.effort;
|
|
585
600
|
}
|
|
586
601
|
else if (mutation.kind === "set-agent-model") {
|
|
602
|
+
if (mutation.requireBuiltinPi && (agent.runtime !== "pi" || agent.piDistribution !== "builtin")) {
|
|
603
|
+
throw new Error(`Agent ${mutation.agentId} 不是内置 Pi`);
|
|
604
|
+
}
|
|
587
605
|
if (!mutation.model.trim())
|
|
588
606
|
throw new Error("model 不能为空");
|
|
589
607
|
assertModel(agent.runtime, mutation.model);
|
|
@@ -734,7 +752,7 @@ function assertConfigRoot(root) {
|
|
|
734
752
|
if (typeof process.getuid === "function" && stat.uid !== process.getuid())
|
|
735
753
|
throw new Error("config root owner is unsafe");
|
|
736
754
|
}
|
|
737
|
-
function
|
|
755
|
+
function acquireConfigLock(layout) {
|
|
738
756
|
assertNoSymlinkAncestors(layout.root);
|
|
739
757
|
fs.mkdirSync(layout.root, { recursive: true, mode: 0o700 });
|
|
740
758
|
const rootStat = fs.lstatSync(layout.root);
|
|
@@ -773,20 +791,43 @@ function withConfigLock(layout, action) {
|
|
|
773
791
|
}
|
|
774
792
|
if (!acquired)
|
|
775
793
|
throw new Error("配置正被其他进程修改,请稍后重试");
|
|
794
|
+
return {
|
|
795
|
+
release() {
|
|
796
|
+
const current = readLockRecord(lock);
|
|
797
|
+
if (current?.record?.nonce === owner.nonce && current.record.pid === owner.pid) {
|
|
798
|
+
try {
|
|
799
|
+
fs.unlinkSync(lock);
|
|
800
|
+
fsyncDirectoryOf(lock);
|
|
801
|
+
}
|
|
802
|
+
catch { /* best effort */ }
|
|
803
|
+
}
|
|
804
|
+
},
|
|
805
|
+
};
|
|
806
|
+
}
|
|
807
|
+
function withConfigLock(layout, action) {
|
|
808
|
+
const held = acquireConfigLock(layout);
|
|
776
809
|
try {
|
|
777
810
|
recoverMigrationJournal(layout.root);
|
|
778
811
|
recoverRollbackJournal(layout.root);
|
|
779
812
|
return action();
|
|
780
813
|
}
|
|
781
814
|
finally {
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
815
|
+
held.release();
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
export function withConfigMutationLock(env, action) {
|
|
819
|
+
return withConfigLock(TargetRootLayout.fromConfigDir(resolveConfigDir(env)), action);
|
|
820
|
+
}
|
|
821
|
+
export async function withConfigMutationLockAsync(env, action) {
|
|
822
|
+
const layout = TargetRootLayout.fromConfigDir(resolveConfigDir(env));
|
|
823
|
+
const held = acquireConfigLock(layout);
|
|
824
|
+
try {
|
|
825
|
+
recoverMigrationJournal(layout.root);
|
|
826
|
+
recoverRollbackJournal(layout.root);
|
|
827
|
+
return await action();
|
|
828
|
+
}
|
|
829
|
+
finally {
|
|
830
|
+
held.release();
|
|
790
831
|
}
|
|
791
832
|
}
|
|
792
833
|
const CONFIG_ROLLBACK_JOURNAL_FILE = ".config-rollback-journal.json";
|
|
@@ -1047,7 +1088,7 @@ export function commitSetupConfig(env, expectedRevision, nextStored) {
|
|
|
1047
1088
|
export function safeConfigView(config, onlyAgentId, chatId, applyState) {
|
|
1048
1089
|
const entries = onlyAgentId ? [[onlyAgentId, config.agents[onlyAgentId]]] : Object.entries(config.agents);
|
|
1049
1090
|
const agents = entries.filter((entry) => Boolean(entry[1])).map(([agentId, agent]) => ({
|
|
1050
|
-
agentId, runtime: agent.runtime, model: agent.model, piDistribution: agent.piDistribution ?? (agent.runtime === "pi" ? "external" : null), effort: agent.effort ?? null,
|
|
1091
|
+
agentId, runtime: agent.runtime, runtimeOption: toUserRuntime(agent.runtime, agent.piDistribution), model: agent.model, piDistribution: agent.piDistribution ?? (agent.runtime === "pi" ? "external" : null), effort: agent.effort ?? null,
|
|
1051
1092
|
mention: {
|
|
1052
1093
|
override: agent.mentionPolicy ?? "inherit",
|
|
1053
1094
|
effective: agent.mentionPolicy ?? config.mentionPolicy,
|