oasis_test_v2 2.2.3 → 2.2.4
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/index.js +194 -15
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -24008,6 +24008,13 @@ function applyModelOverrides(base, overrides) {
|
|
|
24008
24008
|
}
|
|
24009
24009
|
return kept;
|
|
24010
24010
|
}
|
|
24011
|
+
function clearModelDiscoveryCache(runtime, executablePath) {
|
|
24012
|
+
if (!runtime) {
|
|
24013
|
+
modelCache.clear();
|
|
24014
|
+
return;
|
|
24015
|
+
}
|
|
24016
|
+
modelCache.delete(discoveryCacheKey(runtime, executablePath));
|
|
24017
|
+
}
|
|
24011
24018
|
function discoveryCacheKey(runtime, executablePath) {
|
|
24012
24019
|
return `${runtime}:${executablePath ?? ""}`;
|
|
24013
24020
|
}
|
|
@@ -24032,8 +24039,11 @@ async function withFallback(runtime, executablePath, discover, fallback) {
|
|
|
24032
24039
|
}
|
|
24033
24040
|
function claudeStaticModels() {
|
|
24034
24041
|
return [
|
|
24035
|
-
{ id: "claude-opus-
|
|
24042
|
+
{ id: "claude-opus-5", label: "Claude Opus 5", provider: "Anthropic" },
|
|
24043
|
+
{ id: "claude-fable-5-1", label: "Claude Fable 5.1", provider: "Anthropic" },
|
|
24044
|
+
{ id: "claude-fable-5", label: "Claude Fable 5", provider: "Anthropic" },
|
|
24036
24045
|
{ id: "claude-opus-4-8", label: "Claude Opus 4.8", provider: "Anthropic" },
|
|
24046
|
+
{ id: "claude-opus-4-7", label: "Claude Opus 4.7", provider: "Anthropic" },
|
|
24037
24047
|
{ id: "claude-opus-4-6", label: "Claude Opus 4.6", provider: "Anthropic" },
|
|
24038
24048
|
{ id: "claude-sonnet-5", label: "Claude Sonnet 5", provider: "Anthropic" },
|
|
24039
24049
|
{ id: "claude-sonnet-4-6", label: "Claude Sonnet 4.6", provider: "Anthropic" },
|
|
@@ -24043,14 +24053,12 @@ function claudeStaticModels() {
|
|
|
24043
24053
|
}
|
|
24044
24054
|
function codexStaticModels() {
|
|
24045
24055
|
return [
|
|
24046
|
-
{ id: "gpt-
|
|
24047
|
-
{ id: "gpt-5.
|
|
24048
|
-
{ id: "gpt-5.
|
|
24049
|
-
{ id: "gpt-5.
|
|
24050
|
-
{ id: "gpt-5.
|
|
24051
|
-
{ id: "gpt-5", label: "GPT-5", provider: "OpenAI" }
|
|
24052
|
-
{ id: "o3", label: "o3", provider: "OpenAI" },
|
|
24053
|
-
{ id: "o3-mini", label: "o3-mini", provider: "OpenAI" }
|
|
24056
|
+
{ id: "gpt-6-astra", label: "GPT-6-Astra", provider: "OpenAI", default: true },
|
|
24057
|
+
{ id: "gpt-5.6-sol", label: "GPT-5.6-Sol", provider: "OpenAI" },
|
|
24058
|
+
{ id: "gpt-5.6-terra", label: "GPT-5.6-Terra", provider: "OpenAI" },
|
|
24059
|
+
{ id: "gpt-5.6-luna", label: "GPT-5.6-Luna", provider: "OpenAI" },
|
|
24060
|
+
{ id: "gpt-5.5", label: "GPT-5.5", provider: "OpenAI" },
|
|
24061
|
+
{ id: "gpt-5.2", label: "GPT-5.2", provider: "OpenAI" }
|
|
24054
24062
|
];
|
|
24055
24063
|
}
|
|
24056
24064
|
function geminiStaticModels() {
|
|
@@ -218483,6 +218491,31 @@ ${input.description}
|
|
|
218483
218491
|
listActorConnectorConnections(actorId) {
|
|
218484
218492
|
return this.opts.store.listActorConnectorConnections(actorId);
|
|
218485
218493
|
}
|
|
218494
|
+
/**
|
|
218495
|
+
* 移除某员工与某连接器的连接(组织页连接器详情的「移除连接」,2026-09-09 原型 1600:5765)。
|
|
218496
|
+
*
|
|
218497
|
+
* 删两样东西,缺一不可:
|
|
218498
|
+
* ① 这名员工**自己**那份连接器凭据(`scope=personal` 且 `connectorId` 命中的变量行)——
|
|
218499
|
+
* 不删的话,「移除」之后 `actorConnected` 里还有它,卡片照样在,读作「删不掉」;
|
|
218500
|
+
* ② 「员工×连接器」的连接记录——不删的话 `effective` 里还有它(enabled=false),
|
|
218501
|
+
* 卡片变成一张「已停用」的僵尸卡,而人要的是它消失。
|
|
218502
|
+
*
|
|
218503
|
+
* **不碰组织那条 connector 行**(决策 0080 修订五的同一条理由):组织级连接是别人配的资产,
|
|
218504
|
+
* 一名员工点「移除连接」不该把全组织的连接拆掉。组织级的断开在「管理 > 连接器」。
|
|
218505
|
+
* 于是:组织已连接时,移除个人连接后这名员工会**回落到组织默认**——卡片仍在,但身份那一行
|
|
218506
|
+
* 变回组织账号。这是对的,不是没删干净。
|
|
218507
|
+
*
|
|
218508
|
+
* 幂等:没有个人凭据、没有记录时照样返回成功(`variablesDeleted: 0`)——重复点、并发点都不该报错。
|
|
218509
|
+
*/
|
|
218510
|
+
async removeActorConnector(actorId, connectorId) {
|
|
218511
|
+
const rows = await this.opts.store.listVariables(actorId);
|
|
218512
|
+
const mine = rows.filter(
|
|
218513
|
+
(v2) => v2.scope === "personal" && v2.actorId === actorId && v2.connectorId === connectorId
|
|
218514
|
+
);
|
|
218515
|
+
for (const v2 of mine) await this.opts.store.deleteVariable(v2.key, actorId);
|
|
218516
|
+
await this.opts.store.deleteActorConnectorConnection(actorId, connectorId);
|
|
218517
|
+
return { removed: true, variablesDeleted: mine.length };
|
|
218518
|
+
}
|
|
218486
218519
|
/**
|
|
218487
218520
|
* 员工连接器面板所需状态:连接记录 + 组织级已连接集合 + 该员工已授权(有个人 connector 变量)集合。
|
|
218488
218521
|
* 前端据此算每个 connector 的 hasRecord / 有效 enabled / connected(actor 或 global)。
|
|
@@ -219282,15 +219315,28 @@ var init_model_pricing = __esm({
|
|
|
219282
219315
|
"gpt-4.1-nano": usd(0.1, 0.4, 0.025),
|
|
219283
219316
|
"gpt-4.1-nano-2025-04-14": usd(0.1, 0.4, 0.025),
|
|
219284
219317
|
"o4-mini": usd(1.1, 4.4, 0.275),
|
|
219318
|
+
// o3 / o3-mini 在 codex 静态目录里可选,却一直不在价目快照里(费用记 0)。
|
|
219319
|
+
// 这两行按 OpenAI 公开价填,不是智增增快照里的行;供应商价目表同步到时以 DB 为准。
|
|
219320
|
+
"o3": usd(2, 8),
|
|
219321
|
+
"o3-mini": usd(1.1, 4.4),
|
|
219322
|
+
"claude-fable-5-1": usd(10, 50),
|
|
219285
219323
|
"claude-fable-5": usd(10, 50),
|
|
219324
|
+
"claude-mythos-5-1": usd(10, 50),
|
|
219286
219325
|
"claude-mythos-5": usd(10, 50),
|
|
219326
|
+
// claude-opus-5 是 Claude Code 当代默认款,却一直不在这张快照里:查不到价 → 费用记 0
|
|
219327
|
+
// (与 2026-09-04 那次 `claude-opus-5[1m]` 记 0 同一类坑)。按 Opus 档 $5/$25 补上。
|
|
219328
|
+
"claude-opus-5": usd(5, 25),
|
|
219287
219329
|
"claude-opus-4-8": usd(5, 25),
|
|
219288
219330
|
"claude-opus-4-7": usd(5, 25),
|
|
219289
219331
|
"claude-sonnet-5": usd(2, 10),
|
|
219290
219332
|
"claude-sonnet-4-6": usd(3, 15),
|
|
219291
219333
|
"claude-opus-4-6": usd(5, 25),
|
|
219292
219334
|
"claude-opus-4-5-20251101": usd(5, 25),
|
|
219335
|
+
"claude-opus-4-5": usd(5, 25),
|
|
219293
219336
|
"claude-sonnet-4-5-20250929": usd(3, 15),
|
|
219337
|
+
// 短名同样要有:前缀比对是「表里的键是模型名的前缀」,带日期的那行匹配不上不带日期的短名。
|
|
219338
|
+
// claude-sonnet-4-5 从 2026-07-04 起就在目录里可选,却一直查不到价(费用记 0),本次一并补。
|
|
219339
|
+
"claude-sonnet-4-5": usd(3, 15),
|
|
219294
219340
|
"claude-opus-4-1-20250805": usd(15, 75),
|
|
219295
219341
|
"claude-opus-4-20250514": usd(15, 75),
|
|
219296
219342
|
"claude-sonnet-4-20250514": usd(3, 15),
|
|
@@ -219299,6 +219345,14 @@ var init_model_pricing = __esm({
|
|
|
219299
219345
|
"claude-3-5-sonnet-20240620": usd(3, 15),
|
|
219300
219346
|
"claude-3-sonnet-20240229": usd(3, 15),
|
|
219301
219347
|
"claude-haiku-4-5-20251001": usd(1, 5),
|
|
219348
|
+
// codebuddy 目录用点号写法(claude-sonnet-4.6),与上面的连字符写法是同一批模型,
|
|
219349
|
+
// 但字符串对不上就查不到价 → 记 0。同价另起别名行。
|
|
219350
|
+
"claude-sonnet-4.6": usd(3, 15),
|
|
219351
|
+
"claude-opus-4.7": usd(5, 25),
|
|
219352
|
+
"gemini-3.1-pro": usd(2, 12),
|
|
219353
|
+
"gemini-3-pro-preview": usd(2, 12),
|
|
219354
|
+
// Claude Code 回报的可能是不带日期的短名,短名匹配不上带日期的那行(前缀比对是「表里的键是模型名的前缀」)。
|
|
219355
|
+
"claude-haiku-4-5": usd(1, 5),
|
|
219302
219356
|
"gemini-3.5-flash": usd(1.5, 9),
|
|
219303
219357
|
"gemini-3.1-pro-preview": usd(2, 12),
|
|
219304
219358
|
"gemini-3.1-pro-preview-customtools": usd(2, 12),
|
|
@@ -220432,6 +220486,11 @@ function actorsDomain(opts) {
|
|
|
220432
220486
|
const conn = await service.setActorConnectorEnabled(req.params.id, req.params.connectorId, b2.enabled);
|
|
220433
220487
|
return { status: 200, body: conn };
|
|
220434
220488
|
});
|
|
220489
|
+
router.delete("/api/actors/:id/connectors/:connectorId", async (req) => {
|
|
220490
|
+
const { service } = await resolveCtx(req.auth.companyId);
|
|
220491
|
+
const r = await service.removeActorConnector(req.params.id, req.params.connectorId);
|
|
220492
|
+
return { status: 200, body: r };
|
|
220493
|
+
});
|
|
220435
220494
|
const requireVariableManager = (req) => {
|
|
220436
220495
|
if (!isHumanActor(req.auth.actor)) {
|
|
220437
220496
|
throw new ApiError(
|
|
@@ -224723,11 +224782,13 @@ async function resolveRuntimeModels(deps, runtimeId) {
|
|
|
224723
224782
|
const rt = (await deps.nodeStore.listRuntimes()).find((r) => r.id === runtimeId);
|
|
224724
224783
|
if (!rt) return [];
|
|
224725
224784
|
try {
|
|
224726
|
-
const
|
|
224727
|
-
|
|
224785
|
+
const reported = deps.nodeReportedModels?.(rt.nodeId, rt.kind);
|
|
224786
|
+
const [discovered, overrides] = await Promise.all([
|
|
224787
|
+
// 节点报过就不必再在控制面上白 spawn 一次(跨机时那次 spawn 注定 ENOENT)。
|
|
224788
|
+
reported && reported.length > 0 ? Promise.resolve(reported) : listModels(rt.kind, rt.binary),
|
|
224728
224789
|
deps.registry.listRuntimeModelOverrides(runtimeId)
|
|
224729
224790
|
]);
|
|
224730
|
-
return applyModelOverrides(
|
|
224791
|
+
return applyModelOverrides(discovered, overrides);
|
|
224731
224792
|
} catch {
|
|
224732
224793
|
const overrides = await deps.registry.listRuntimeModelOverrides(runtimeId).catch(() => []);
|
|
224733
224794
|
return applyModelOverrides([], overrides);
|
|
@@ -225119,6 +225180,21 @@ function nodesDomain(deps) {
|
|
|
225119
225180
|
if (!rt) return { status: 404, body: { error: "runtime not found" } };
|
|
225120
225181
|
return { status: 200, body: { items: await resolveRuntimeModels(deps, runtimeId) } };
|
|
225121
225182
|
});
|
|
225183
|
+
router.post("/api/runtimes/:runtimeId/models/refresh", async (req) => {
|
|
225184
|
+
const runtimeId = req.params["runtimeId"];
|
|
225185
|
+
if (!runtimeId) return { status: 400, body: { error: "missing runtimeId" } };
|
|
225186
|
+
const rt = (await deps.nodeStore.listRuntimes()).find((r) => r.id === runtimeId);
|
|
225187
|
+
if (!rt) return { status: 404, body: { error: "runtime not found" } };
|
|
225188
|
+
const outcome = deps.refreshNodeModels ? await deps.refreshNodeModels(rt.nodeId) : { ok: false, reason: "\u672C\u90E8\u7F72\u6CA1\u6709\u8282\u70B9\u7F51\u5173\uFF0C\u62FF\u4E0D\u5230\u8FD9\u53F0\u673A\u5668\u4E0A\u7684\u771F\u5B9E\u6E05\u5355" };
|
|
225189
|
+
return {
|
|
225190
|
+
status: 200,
|
|
225191
|
+
body: {
|
|
225192
|
+
items: await resolveRuntimeModels(deps, runtimeId),
|
|
225193
|
+
refreshed: outcome.ok,
|
|
225194
|
+
...outcome.reason ? { reason: outcome.reason } : {}
|
|
225195
|
+
}
|
|
225196
|
+
};
|
|
225197
|
+
});
|
|
225122
225198
|
router.get("/api/runtimes/:runtimeId/model-overrides", async (req) => {
|
|
225123
225199
|
const runtimeId = req.params["runtimeId"];
|
|
225124
225200
|
if (!runtimeId) return { status: 400, body: { error: "missing runtimeId" } };
|
|
@@ -256820,6 +256896,41 @@ async function startServe(opts) {
|
|
|
256820
256896
|
let nodeTokens = createNodeTokenStore(path29.join(opts.dir, "node-tokens.json"));
|
|
256821
256897
|
const enrollTokens = createEnrollTokenStore(30 * 60 * 1e3, path29.join(opts.dir, "enroll-tokens.json"));
|
|
256822
256898
|
let nodeStore = await FileNodeStore.open(path29.join(opts.dir, "nodes.json"));
|
|
256899
|
+
const nodeReportedModelsStore = /* @__PURE__ */ new Map();
|
|
256900
|
+
const modelRefreshWaiters = /* @__PURE__ */ new Map();
|
|
256901
|
+
const modelRefreshInFlight = /* @__PURE__ */ new Map();
|
|
256902
|
+
const modelRefreshLastAt = /* @__PURE__ */ new Map();
|
|
256903
|
+
const MODELS_STALE_MS = 5 * 6e4;
|
|
256904
|
+
const MODELS_BG_REFRESH_MIN_GAP_MS = 6e4;
|
|
256905
|
+
const MODELS_REFRESH_TIMEOUT_MS = 45e3;
|
|
256906
|
+
const refreshNodeModels = (nodeId) => {
|
|
256907
|
+
const running = modelRefreshInFlight.get(nodeId);
|
|
256908
|
+
if (running) return running;
|
|
256909
|
+
if (!hub) return Promise.resolve({ ok: false, reason: "\u672C\u8FDB\u7A0B\u6CA1\u6709\u8282\u70B9\u7F51\u5173" });
|
|
256910
|
+
const online = hub.connectedDaemons().some((d) => d.daemonId === nodeId);
|
|
256911
|
+
if (!online) return Promise.resolve({ ok: false, reason: "\u8282\u70B9\u5F53\u524D\u4E0D\u5728\u7EBF\uFF0C\u7528\u7684\u662F\u5B83\u4E0A\u6B21\u62A5\u7684\u6E05\u5355" });
|
|
256912
|
+
const requestId = (0, import_node_crypto75.randomUUID)();
|
|
256913
|
+
const task = new Promise((resolve10) => {
|
|
256914
|
+
const timer = setTimeout(() => {
|
|
256915
|
+
modelRefreshWaiters.delete(requestId);
|
|
256916
|
+
resolve10({ ok: false, reason: "\u8282\u70B9\u6CA1\u5728 45 \u79D2\u5185\u56DE\u8BDD\uFF08\u53EF\u80FD\u662F\u65E7\u7248\u8282\u70B9\uFF0C\u6216\u8FD9\u53F0\u673A\u5668\u4E0A\u7684 CLI \u63A2\u6D4B\u8D85\u65F6\uFF09" });
|
|
256917
|
+
}, MODELS_REFRESH_TIMEOUT_MS);
|
|
256918
|
+
modelRefreshWaiters.set(requestId, { resolve: () => resolve10({ ok: true }), timer });
|
|
256919
|
+
hub.dispatch(nodeId, { type: "list_models", requestId });
|
|
256920
|
+
}).finally(() => {
|
|
256921
|
+
modelRefreshInFlight.delete(nodeId);
|
|
256922
|
+
modelRefreshLastAt.set(nodeId, Date.now());
|
|
256923
|
+
});
|
|
256924
|
+
modelRefreshInFlight.set(nodeId, task);
|
|
256925
|
+
return task;
|
|
256926
|
+
};
|
|
256927
|
+
const nodeReportedModels = (nodeId, runtimeKind) => {
|
|
256928
|
+
const entry = nodeReportedModelsStore.get(nodeId);
|
|
256929
|
+
const stale = !entry || Date.now() - entry.fetchedAt > MODELS_STALE_MS;
|
|
256930
|
+
const gapOk = Date.now() - (modelRefreshLastAt.get(nodeId) ?? 0) > MODELS_BG_REFRESH_MIN_GAP_MS;
|
|
256931
|
+
if (stale && gapOk) void refreshNodeModels(nodeId).catch(() => ({ ok: false }));
|
|
256932
|
+
return entry?.byKind.get(runtimeKind);
|
|
256933
|
+
};
|
|
256823
256934
|
const registryAuditFile = path29.join(opts.dir, "registry-audit.ndjson");
|
|
256824
256935
|
const registryListeners = /* @__PURE__ */ new Set();
|
|
256825
256936
|
const registryAudit = (record8) => {
|
|
@@ -256949,7 +257060,7 @@ async function startServe(opts) {
|
|
|
256949
257060
|
listBindingModelIds: async (nodeId, runtimeKind) => {
|
|
256950
257061
|
const rt = (await nodeStore.listRuntimes(nodeId)).find((r) => r.kind === runtimeKind);
|
|
256951
257062
|
if (!rt) return [];
|
|
256952
|
-
return (await resolveRuntimeModels({ nodeStore, registry: registryStore }, rt.id)).map((m2) => m2.id);
|
|
257063
|
+
return (await resolveRuntimeModels({ nodeStore, registry: registryStore, nodeReportedModels }, rt.id)).map((m2) => m2.id);
|
|
256953
257064
|
}
|
|
256954
257065
|
});
|
|
256955
257066
|
assistantsService = new AssistantsService({
|
|
@@ -258487,7 +258598,7 @@ async function startServe(opts) {
|
|
|
258487
258598
|
registry: registryStore,
|
|
258488
258599
|
// 会话级模型覆盖的候选清单:与 `GET /api/runtimes/:id/models` **同一份**实现
|
|
258489
258600
|
// (resolveRuntimeModels = discovery + 管理员 override),避免「下拉选得到、发出去被拒」。
|
|
258490
|
-
listRuntimeModelIds: async (runtimeId) => (await resolveRuntimeModels({ nodeStore, registry: registryStore }, runtimeId)).map((m2) => m2.id),
|
|
258601
|
+
listRuntimeModelIds: async (runtimeId) => (await resolveRuntimeModels({ nodeStore, registry: registryStore, nodeReportedModels }, runtimeId)).map((m2) => m2.id),
|
|
258491
258602
|
// 诊断 ab94f202 Fix A:add-revision --role 写入口校验用「可分配岗位」集合(岗位目录 AND assignable)。
|
|
258492
258603
|
// 与 GET /api/roles 的 assignable 派生同式(domains/roles/index.ts):system=true / 已弃用一律不可分配。
|
|
258493
258604
|
resolveAssignableRoles: async () => new Set(
|
|
@@ -258624,6 +258735,8 @@ async function startServe(opts) {
|
|
|
258624
258735
|
nodeHealth,
|
|
258625
258736
|
activeRunCountOf,
|
|
258626
258737
|
activeRunsOf,
|
|
258738
|
+
nodeReportedModels,
|
|
258739
|
+
refreshNodeModels,
|
|
258627
258740
|
fetchLatestNpmDaemonVersion
|
|
258628
258741
|
}),
|
|
258629
258742
|
collabDomain({
|
|
@@ -259933,6 +260046,24 @@ async function startServe(opts) {
|
|
|
259933
260046
|
});
|
|
259934
260047
|
return chatLiveSessions.has(jobKey) ? "live" : "unknown";
|
|
259935
260048
|
});
|
|
260049
|
+
hub.addMessageListener((daemonId, msg) => {
|
|
260050
|
+
if (msg.type !== "runtime_models") return;
|
|
260051
|
+
const prev = nodeReportedModelsStore.get(daemonId);
|
|
260052
|
+
const byKind = prev?.byKind ?? /* @__PURE__ */ new Map();
|
|
260053
|
+
for (const entry of msg.models) {
|
|
260054
|
+
if (entry.models.length > 0) byKind.set(entry.kind, entry.models);
|
|
260055
|
+
}
|
|
260056
|
+
nodeReportedModelsStore.set(daemonId, { byKind, fetchedAt: Date.now() });
|
|
260057
|
+
if (msg.requestId) {
|
|
260058
|
+
const waiter = modelRefreshWaiters.get(msg.requestId);
|
|
260059
|
+
if (waiter) {
|
|
260060
|
+
clearTimeout(waiter.timer);
|
|
260061
|
+
modelRefreshWaiters.delete(msg.requestId);
|
|
260062
|
+
waiter.resolve();
|
|
260063
|
+
}
|
|
260064
|
+
}
|
|
260065
|
+
console.log(`[models] \u8282\u70B9 ${daemonId} \u4E0A\u62A5\u5019\u9009\u6A21\u578B\uFF1A${msg.models.map((m2) => `${m2.kind}=${m2.models.length}`).join(" ") || "\uFF08\u4E00\u6761\u90FD\u6CA1\u63A2\u5230\uFF09"}`);
|
|
260066
|
+
});
|
|
259936
260067
|
hub.addMessageListener((daemonId, msg) => {
|
|
259937
260068
|
if (msg.type !== "gc_query_artifacts") return;
|
|
259938
260069
|
void (async () => {
|
|
@@ -263036,6 +263167,7 @@ var OUTBOX_MAX = 500;
|
|
|
263036
263167
|
var PENDING_STREAM_MAX = 2e3;
|
|
263037
263168
|
var AUTH_REJECT_BACKOFF_MAX_MS = 15 * 6e4;
|
|
263038
263169
|
var AUTH_REJECT_GIVE_UP_AFTER = 3;
|
|
263170
|
+
var MODEL_REPORT_COOLDOWN_MS = 10 * 6e4;
|
|
263039
263171
|
var AUTH_REJECT_RE = /Unexpected server response:\s*(401|403)/;
|
|
263040
263172
|
var DRAIN_TIMEOUT_MS = 15e3;
|
|
263041
263173
|
var DRAIN_POLL_MS = 50;
|
|
@@ -263129,6 +263261,12 @@ var DaemonWsClient = class {
|
|
|
263129
263261
|
authRejectStreak = 0;
|
|
263130
263262
|
/** 本次连接尝试是否因握手 401/403 失败——error 事件里置、close 事件里消费。 */
|
|
263131
263263
|
lastErrorWasAuthReject = false;
|
|
263264
|
+
/** 模型上报的轮次号:重连会再拉一轮,用它作废上一轮的迟到结果(否则旧结果可能盖住新结果)。 */
|
|
263265
|
+
modelReportGeneration = 0;
|
|
263266
|
+
/** 上一次**探测成功**的时刻;节点频繁掉线重连时靠它避免每分钟把十几个 CLI 重起一遍。 */
|
|
263267
|
+
lastModelReportAt = 0;
|
|
263268
|
+
/** 缓存上一轮结果:冷却期内重连直接重发这份,服务端重启后也能立刻拿到清单。 */
|
|
263269
|
+
lastModelReport = [];
|
|
263132
263270
|
authRejectGiveUpAfter;
|
|
263133
263271
|
/** 放弃时的动作;默认干净退出(exit 0),测试注入以免打死测试进程。 */
|
|
263134
263272
|
onAuthGiveUp;
|
|
@@ -263237,6 +263375,7 @@ var DaemonWsClient = class {
|
|
|
263237
263375
|
this.flushPendingStream();
|
|
263238
263376
|
this.resendOutbox();
|
|
263239
263377
|
this.reportRuntimes = false;
|
|
263378
|
+
void this.reportRuntimeModels();
|
|
263240
263379
|
this.pingTimer = setInterval(() => {
|
|
263241
263380
|
this.send({ type: "pong" });
|
|
263242
263381
|
if (Date.now() - this.lastReceivedAt > this.silenceTimeoutMs) {
|
|
@@ -263403,6 +263542,10 @@ var DaemonWsClient = class {
|
|
|
263403
263542
|
this.send({ type: "workdir_read_result", requestId: msg.requestId, result });
|
|
263404
263543
|
break;
|
|
263405
263544
|
}
|
|
263545
|
+
case "list_models": {
|
|
263546
|
+
void this.reportRuntimeModels({ force: true, requestId: msg.requestId });
|
|
263547
|
+
break;
|
|
263548
|
+
}
|
|
263406
263549
|
case "update": {
|
|
263407
263550
|
this.pendingUpdatePkg = msg.pkg;
|
|
263408
263551
|
if (!this.onUpdate) {
|
|
@@ -263520,6 +263663,42 @@ var DaemonWsClient = class {
|
|
|
263520
263663
|
this.onUpdate?.(this.pendingUpdatePkg);
|
|
263521
263664
|
}
|
|
263522
263665
|
}
|
|
263666
|
+
/**
|
|
263667
|
+
* 拉一遍本机各 runtime 的候选模型清单并上报(`runtime_models` 帧)。
|
|
263668
|
+
*
|
|
263669
|
+
* 串行而不是并发:ACP 家族每探一个都要真起一个 CLI 进程(hermes 40s、oasis-agent 30s 的超时),
|
|
263670
|
+
* 十几个一起起会把节点的内存和文件句柄按住。`listModels` 自带 60 秒缓存,重连时基本是空跑。
|
|
263671
|
+
* 任何一个 runtime 抛错都只丢它自己那一条,不影响其余。全空就不发帧——让服务端走老路,
|
|
263672
|
+
* 而不是用一份空清单把它原本能给出的静态目录盖掉。
|
|
263673
|
+
*/
|
|
263674
|
+
async reportRuntimeModels(opts = {}) {
|
|
263675
|
+
const generation = ++this.modelReportGeneration;
|
|
263676
|
+
const reply = (models) => this.send({ type: "runtime_models", models, ...opts.requestId ? { requestId: opts.requestId } : {} });
|
|
263677
|
+
if (!opts.force && this.lastModelReport.length > 0 && Date.now() - this.lastModelReportAt < MODEL_REPORT_COOLDOWN_MS) {
|
|
263678
|
+
reply(this.lastModelReport);
|
|
263679
|
+
return;
|
|
263680
|
+
}
|
|
263681
|
+
const out = [];
|
|
263682
|
+
for (const rt of this.runtimes) {
|
|
263683
|
+
if (generation !== this.modelReportGeneration) return;
|
|
263684
|
+
try {
|
|
263685
|
+
const kind = rt.kind;
|
|
263686
|
+
if (opts.force) clearModelDiscoveryCache(kind, rt.binary);
|
|
263687
|
+
const models = await listModels(kind, rt.binary);
|
|
263688
|
+
if (models.length > 0) out.push({ kind: rt.kind, models });
|
|
263689
|
+
} catch {
|
|
263690
|
+
}
|
|
263691
|
+
}
|
|
263692
|
+
if (generation !== this.modelReportGeneration) return;
|
|
263693
|
+
if (out.length === 0) {
|
|
263694
|
+
if (opts.requestId) reply([]);
|
|
263695
|
+
return;
|
|
263696
|
+
}
|
|
263697
|
+
this.lastModelReport = out;
|
|
263698
|
+
this.lastModelReportAt = Date.now();
|
|
263699
|
+
reply(out);
|
|
263700
|
+
log2("[node-cli]", `\u5DF2\u4E0A\u62A5\u5019\u9009\u6A21\u578B\uFF1A${out.map((r) => `${r.kind}=${r.models.length}`).join(" ")}`);
|
|
263701
|
+
}
|
|
263523
263702
|
buildMeta() {
|
|
263524
263703
|
const activeSessions = this.sessions.activeSessions();
|
|
263525
263704
|
return {
|
|
@@ -269401,7 +269580,7 @@ function shimScript() {
|
|
|
269401
269580
|
}
|
|
269402
269581
|
|
|
269403
269582
|
// src/index.ts
|
|
269404
|
-
var PKG_VERSION = true ? "2.2.
|
|
269583
|
+
var PKG_VERSION = true ? "2.2.4" : "dev";
|
|
269405
269584
|
var LOCAL_BIN = localBin();
|
|
269406
269585
|
var NPM_PREFIX = npmPrefix();
|
|
269407
269586
|
var INSTANCE = DEFAULT_INSTANCE;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "oasis_test_v2",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.4",
|
|
4
4
|
"description": "Oasis node daemon + CLI — background daemon, auto-start, full server CLI",
|
|
5
5
|
"bin": {
|
|
6
6
|
"oasis": "./dist/index.js"
|
|
@@ -26,6 +26,6 @@
|
|
|
26
26
|
"node": ">=20"
|
|
27
27
|
},
|
|
28
28
|
"oasisRelease": {
|
|
29
|
-
"sourceHead": "
|
|
29
|
+
"sourceHead": "1488999e5b4e5658ae63be219fd34f59ae74705e"
|
|
30
30
|
}
|
|
31
31
|
}
|